Contents
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. |
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. |
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.