From wiki.ginstr.com
Revision as of 11:55, 9 February 2021 by Wikiadmin (talk | contribs) (Scanning)
Jump to: navigation, search

Java class for direct interacting with ginstr IIoT device through Bluetooth LE interface.

IIoT class helps to create device object and provides the access to the device's hardware and software features using Bluetooth LE connection.
The functionality of the described class is based on the “BLESSED for Android” library ([[1]]), licensed under MIT. This lib provides methods for BLE interaction.

Methods of IIoT class can be applied without pairing with devices, which allows configuring/managing plenty of devices during one session.

Work with devices

After Bluetooth device was enabled, on the side of the ESP32 based IIoT device the BLE server with GATT profile was created.


GATT structure

This server contains:

Name UUID Description
SERVICE
MAIN_SERVICE 6cca7d41-2342-4239-9e9b-adbece2094b0 The main device GATT service. By this service number it is possible to filter ginstr devices
CHARACTERISTICS
DIRECT_CONTROL_CHAR 53dae9e0-f30f-449f-be52-2e53df7c83b8

This characteristic is used for the main interacting workflow. Can be read / or written with a response.
The device`s firmware uses “onwrite” callback for the direct processing of commands that were written in this characteristic.

DIRECT_READ_CHAR a95238b5-3c8d-493b-8ef7-5b3afa695cf6 This characteristic is used for response reading.

After sending some read commands into the DIRECT_CONTROL_CHAR, the result of the reading will be written to DIRECT_READ_CHAR.
After reading, the notification will be triggered and characteristic payload can be captured with help of the onCharacteristicUpdate callback method, provided by the BLEssed library.
The filtering of incoming payloads is done by the command code containing.

STREAM_BUFFER_CHAR 53a60fb7-536d-412d-a86b-0145f1a30d01 This characteristic is used for transmission of big files, as long as GATT characteristic has a size limit of 20 bytes.
During data transmission, the chunks of the message appear in this characteristic. After reading, the new one is written.
STREAM_FEATURES_CHAR 552c03a0-eb9c-4c1b-a811-09a135d6eb8d This characteristic is used for transmitting the additional features of transmitted data, such as crc32 hash and total chunks number.

Scanning

To get the list of available devices the scanForPeripherals() from the BLEssed library can be used.
To get ONLY the list of ginstr IIoT devices, it is helpful to scan with filtering features with help of method scanForPeripheralsWithServices(UUID[] serviceUUIDs).
As long as all ginstr devices would use the same MAIN_SERVICE uncial UUIDs, the scan result would always contain ginstr devices only.

After scanning, the discovered periphery objects (IIoT devices) will appear in the onDiscoveredPeripheral() callback from the BLEssed library.

To init the device, it is important to add the discovered device as a parameter into IIoT class constructor, which can be done from the device discovered callback:

public List<IIoT> discoveredDevicesList; 
....
public void onDiscoveredPeripheral( BluetoothPeripheral peripheral, ScanResult scanResult ) {
Log.d("----NAME", scanResult.getScanRecord().getDeviceName());
Log.d("----ADDRESS",scanResult.getDevice().getAddress());
IIoT dev = new IIoT(peripheral);
discoveredDevicesList.add(dev);
}


Discovered and created device objects can be stored in the global list object.

Before operations, the device should be connected with help of BLEssed library method from created central Bluetooth object:

central.connectPeripheral( discoveredDevicesList.get(0).peripheral, peripheralCallback );

Getting the device features

Device address the address can be obtained directly from the periphery features:

IIoT dev = new IIoT(peripheral);
String address = dev.getAddress()

Serial number: The serial number can be requested by calling the IIoT class method getSerialNumber().

IIoT dev = new IIoT(peripheral);
boolean success = dev.getSerialNumber();


After request, the result would be captured by onCharacteristicUpdate callback and filtered by getting serial command content.

Work with config files

Uploading configuration XML file

The configuration file has an XML structure and can be loaded into device memory as a string to be parsed into configuration object on the firmware side further.

To load the config file as a string into the chosen device, there is IIoT class method setConfigFile(String configFile) used.
This method calculates CRC32 hash of the string, breaks it into chunks, and transmits it sequentially into the peripheral device.

Downloading configuration XML

To download configuration XML stored in the devices EEPROM memory, there is IIoT class method getConfigFileDevice() used.
This method makes a request, after which device starts transmitting the chunks of the file stored in the memory and used for configuration object generation.

After the file downloading request is firing up, the stream receiving mode appears activated by setting up the IIoT class flag STREAM_DIRECTION to IN.

The incoming payload packets are capturing by onCharacteristicUpdate() callback method from BLEssed library and can be filtered by Characteristic UUID, as long as for data stream transmission the STREAM_BUFFER_CHAR is used.
When the stream is started, there is another one characteristic appears updated: STREAM_FEATURES_CHAR.
This characteristic holds the CRC32 hash of the string and total chunks number.

While new chunks are receiving, if the received chunk number is less than the size of the string in these chunks, the received chunk appends to the temporary buffer string object in the IIoT class.
If the last chunk received, the CRC32 hash from the buffered string is calculated.
If the calculated CRC32 is equal to CRC32 from STREAM_FEATURES_CHAR, it is assumed that the string is valid and the receiving process was successful.
After this, the IIoT class flag streamStatus get the SUCCESS value and the compiled string can be yielded from IIoT class String object LoadedFromStream.

Getting current config hash

To get the configuration hash stored in device, there is IIoT class method getConfigHash() used.

The received payload can be captured in onCharacteristicUpdate() callback and filtered out by command ID.

Work with error log

The error log can be loaded in a way similar to downloading the configuration XML.
After loading from the device's EEPROM memory, the table with error codes and timestamps appears converted into a delimiter separated string.
The IIoT class method getConfigUpdateErrorLogFromDevice() is used.
After the request is done, the stream type is switched by setting up the IIoT class flag streamType to ERRORS value.
When a loaded string appears been loaded in the IIoT class string object LoadedFromStream, it can be converted to the HashMap<Long, Character> by calling IIoT method getErrorsHashMap(String errorsString).
The Long key from the HashMap would store timestamp value in UNIX format when character value would store error code

Operations with onboard periphery

The IIoT class provides methods for accessing the onboard periphery devices directly.

Ginstr IIoT device has a broad set of additional ports. Some of these ports are internally connected to the onboard devices, others can be configured for controlling the external devices, which is useful in case of work with a broad set of extension boards, expanding functionality and use cases.


Ports table

List of the physical ports which can be accessed directly provided in the table below.

* Multiplexed output can be configured as digital input multiplexer, but this is an experimental feature and would not be implemented yet. Also, these ports can be set up to achieve software PWM outputs (not implemented)

** Multiplexed port input can be used as interrupt inputs, but the setup of this feature have a sense with global configuration via XML file.

*** All physical pins accept interrupts digital interfaces and PWM (except pin 1, which is input only), but the setup of this feature have a sense with global configuration via XML file.

Port name Port group Descriptions Functions Port direction
GREEN_LED Onboard indication Port of green indication led Normal logic, the state can be set or read Output only *
AMBER_LED Port of amber indication led
WHITE_LED Port of white indication led
BLUE_LED Port of blue indication led
D_BLUE Port of blue part of blue-red indication cell
D_RED Port of red part of blue-red indication cell
HV_POWERBUS Device power supply 4.0V bus power supply
GNSS_POWER GNSS module power supply
GSM_ON_OFF GSM module power on / off signal
GSM_POWER GSM module power supply
LORA_POWER LoRa module power supply
PERIPHERY_POWER Secondary periphery power management port
POWER_GROUP_B Power supply for the power management group B
POWER_GROUP_C Power supply for the power management group C
MUXOUT_1 Multiplexed port output Digital output port, can be used for turning on/off external devices Normal or inverted logic can be applied, port state can be set or read
MUXOUT_2
MUXOUT_3
MUXOUT_4
MUXOUT_5
MUXIN_1 Multiplexed port input ** Analogue or digital read port 12-bit multiplexed analogue read, digital read Input only
MUXIN_2
MUXIN_3
MUXIN_4
MUXIN_5
MUXIN_6
MUXIN_7
MUXIN_8
PINPORT_1 Physical pin port *** ESP32 port 39 12-bit direct analogue read, digital read
PINPORT_2 ESP32 port 1 Digital read, digital write, PWM Input / Output
PINPORT_3 ESP32 port 3
PINPORT_4 ESP32 port 4
PINPORT_5 ESP32 port 5
PINPORT_6 ESP32 port 12
PINPORT_7 ESP32 port 32
PINPORT_8 ESP32 port 33
TEMPERATURE_IN Analogue values for the temperature readings Analogue read port Analog read ports for onboard measurements Input only
CURRENT_IN Analog values for the current reading
CAP_VOLTAGE Voltage of the discharging capacitor
PRIM_BAT_VOLTAGE Voltage of the primary battery
SEC_BAT_VOLTAGE Voltage of the secondary coin battery

Inverted and non-inverted states

In the case of the discrete external devices connected (on/off option), there is 2 option of how do these devices can be switched off or on.
To avoid misunderstandings and provide easy to follow logic, for port on/off the inversion enumeration (IIoT.INVERTED.YES / NO) is provided.

According to electronics design, some devices can be activated by a LOW level (logic zero) on input.
Ports with such devices should be used with an inversion flag. Other devices can be activated by HIGH level (logic 1).
Writing and reading the periphery states

Commands bound to perform the read and write operations

The ports that have output port direction can be turned on / off, or PWM can be set up (for physical pins).

Command name Command text Command description
GETSERIAL_COMMAND R@SR; The command used to request the serial number
GETHASH_COMMAND R@HS; The command used to request the current CRC32 hash of the stored configuration file
GETSTATUS_COMMAND R@ST; The command used to request the statuses of the device's ports
GETCONFIG_COMMAND R@CF; The command used to request the configuration file
SETCONFIG_COMMAND W@CF; The command used to initiate the configuration file uploading
GETERRORS_COMMAND R@ER; The command used to request the error logs
IDENTIFY_COMMAND W@BL; The command used to init the led blinking
GETPORT_COMMAND R@PR%<N>; The command used in port reading requests, N equals to Integer, belonged to the appropriate port enumeration
SETPORT_COMMAND W@PR%<N>; The command used in port writing, N equals to Integer, belonged to the appropriate port enumeration
GETREG_COMMAND R@RG%<N>; The command used in register reading requests, N equals to Integer, belonged to the appropriate port enumeration
SETREG_COMMAND W@RG%<N>; The command used in register writing, N equals to Integer, belonged to the appropriate port enumeration

Direct write to port

Discrete writing

For purpose of discrete writing, the IIoT class method writePortDirect(PORT_REG port, POWER_STATE state, INVERSION is_inverted) is used.
This method writes to the chosen device the command, which includes the port enumeration parameter, power state parameter (ON/OFF), and an inversion parameter (YES/NO).
The method returns true if the writing was successful.
So, in the case of calling IIoT method IIoT_device.writePortDirect(IIoT.PORT_REG.GREEN_LED, IIoT.POWER_STATE.ON, IIoT.INVERSION.NO) the green led will be turned on normally.

PWM writing (not implemented completely)

To interact with PwM possibilities of physical ports,the same IIoT class method, but with different parameters writePortDirect(PORT_REG port, Integer frequency, Integer pulseWidth, INVERSION is_inverted) is used.
This method writes to the chosen device the command, which includes the port enumeration parameter, base PWM frequency in Hertz, PWM width (0 -> 100 %), and an inversion parameter (YES/NO).
The method returns true if the writing was successful.
So, in the case of calling IIoT method IIoT_device.writePortDirect(IIoT.PORT_REG.PINPORT_8, 10000, 40, IIoT.INVERSION.NO) the following pin will be configured as PWM output, and pulses on the PINPORT_8 will be produced.

Direct read from port

For the ports, that allow only output port direction, there is only the current set state reading feature available.
In this case, the port state means not the physical value on the output (HIGH/LOW) but the written State.
For the ports that allow input features, the current state can be red with help of IIoT class method readPortDirect(PORT_REG port, PORT_READ_TYPE readType), where readType describes the data, which should be returned.
If readType is DISCRETE, the returning value would be always binary, with this method it is possible to read digital levels from analogue pins.
If readType is RAW, returned from the device value would represent analogue read value.
If calling this method for ports with PWM applied, the raw value will represent the actual PWM width.

The returned value will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by command sign.

Operations with data storage registers

The registers are the key-value storage units that can be used to store the custom values, which can be used in the internal logic.

Table of pre-defined registers

This table describes read-only registers, from which the onboard periphery and sensors telemetry information can be read.

Register name Descriptions Data type
THERMO_NOW_REG Data from a temperature sensor in Celsius degrees Float
CURRENT_NOW_REG Data from power current sensor, uA Float
VOLTAGE_NOW_REG Data from power source voltage sensor, VDC Float
RTC_NOW_REG Current device time in milliseconds Long
POWERON_REG Seconds after last boot Long
BATTERY_TYPE True if the rechargeable battery installed Boolean

Registers reading

For the values of the registers reading, the IIoT class method readRegisterDirect(String key) should be used, where key is the value should be red.

The returned value will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by a command sign.

Registers writing

To set the custom register value, the IIoT class method writeRegisterDirect(String key, int value | String value | float value, boolean value) is used.
This method writes the value of the provided type into the storage with the provided key.

To write the threshold value of some temperature parameter, for example, the method should be used as below:

IIoT_device.writeRegisterDirect("temp1", 23.4);

Helper methods

Device identification

To identify a device among others by visual blinking, the IIoT class method identifyDevice() is used. After calling

IIoT_device.identifyDevice();

The attached device should blink with all leads.

Device state summary hashes

To get the periphery state summary, it is IIoT class method getStatusDevice() is used.
After calling

IIoT_device.getStatusDevice();

The returned data will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by a command sign.
The datatype of the payload is byte[].
This byte array can be decrypted into actual statuses with IIoT class method HashMap<PORT_REG, LOGIC_STATE> decryptStatuses(byte[] hash)

byte[] statuses = statusHash.getBytes();
HashMap<IIoT.PORT_REG, IIoT.LOGIC_STATE> decrypted = IIoT.decryptStatuses(statuses);

where IIoT.PORT_REG corresponds the port register from port registers enumeration, and IIoT.LOGIC_STATE corresponds logic states enumeration, and can get value of either HIGH or LOW

API summary

Enumerations

Name Value Description
GREEN_LED_PORT 0 green led
AMBER_LED_PORT 1 amber led power supply
WHITE_LED_PORT 2 white led power supply
BLUE_LED_PORT 3 blue led power supply
D_BLUE_LED_PORT 4 bicolour led blue part power supply
D_RED_LED_PORT 5 bicolour led blue part power supply
HV_POWERBUS 6 4.0V bus power supply
GNSS_POWER 7 GNSS module power supply
GSM_ON_OFF 8 GSM module power on / off signal
GSM_POWER 9 GSM module power supply
LORA_POWER 10 LoRa module power supply
POWER_GROUP_B 11 Power supply for the power management group B
POWER_GROUP_C 12 Power supply for the power management group C
MUXOUT_1_PORT 13
MUXOUT_2_PORT 14
MUXOUT_3_PORT 15
MUXOUT_4_PORT 16
MUXOUT_5_PORT 17
MUXIN_1_PORT 18
MUXIN_2_PORT 19
MUXIN_3_PORT 20
MUXIN_4_PORT 21
MUXIN_5_PORT 22
MUXIN_6_PORT 23
PINPORT_1_PORT 24
PINPORT_2_PORT 25
PINPORT_3_PORT 26
PINPORT_4_PORT 27
PINPORT_5_PORT 28
PINPORT_6_PORT 29
PINPORT_7_PORT 30
P_POWER_PORT 31
CURRENT_IN 32
TEMPERATURE_IN 33
CAP_VOLTAGE 34
PRIM_BAT_VOLTAGE 35
SEC_BAT_VOLTAGE 36

Methods

public boolean getSerialNumber()

Request the serial number

public boolean getConfigHash()

Method for getting the config from the device

public boolean getStatusDevice() 

Method to get ports statuses

public boolean identifyDevice()

Method for the device identification and led blinking

public boolean writePortDirect(PORT_REG port, POWER_STATE state, INVERSION is_inverted)

Method for direct writing the port state

public boolean writeRegisterDirect(String key, int value)

Method for writing the internal register with an Integer value

public boolean writeRegisterDirect(String key, float value)

Method for writing the internal register with a Float value

public boolean writeRegisterDirect(String key, String value)

Method for writing the internal register with a String value

public boolean writeRegisterDirect(String key, Boolean value)

Method for writing the internal register with a Boolean value

public boolean readRegisterDirect(String key)

Method for requesting the register reading by its key.

public boolean readPortDirect(PORT_REG port, POWER_STATE state)

Method for the port state reading request

public boolean getConfigUpdateErrorLogFromDevice() 

Method for the errors log download request

public boolean getConfigFileDevice () 

Method for the config file download request

public boolean setConfigFile(String configFile)

Method for the config file upload

private static String directWriteCommand(PORT_REG port, POWER_STATE state, INVERSION is_inverted)

Method for the port's direct writing: PORT_REG port - the name of the port's register POWER_STATE state - power state, according to enumeration (ON/OFF), INVERSION is_inverted - port inversion model (YES/NO)

private static String directReadCommand(PORT_REG port)

Method for the port's value reading request: PORT_REG port - the name of the port's register

private boolean sendBytes(byte[] compiled)

Helper method to send the prepared byte buffer

private static List<byte[]> divideArray(byte[] source, int chunksize)

Helper method to convert the byte buffer into the chunks before sending them via data stream

private List<byte[]> getXmlChunks(String xml)

Helper method to convert the String with configuration into chunks with defined size

private byte[] concatBytes(byte[] a, byte[] b)

Helper method to simplify the byte buffer concatenations

private byte[] getXmlFeatures(String xml)

Helper method to get the features used by a stream to transfer the configuration file. The return value contains the concatenated values with CRC32 and a chunk number value

public STREAM_STATUS streamReceiver(byte[] chunk)

Helper method to get the current streaming status: important step after each chunk receiving.

public HashMap<Long, Character> getErrorsHashMap(String errorsString)

Helper method to parse the error log, loaded by the stream, into a hash map.

public HashMap<PORT_REG, LOGIC_STATE> decryptStatuses(byte[] hash)

Helper method to parse the port states response into a hash map.