From wiki.ginstr.com
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.

First initialization

After first initialization and before the first config file will be loaded, the device will hold the default values:
Bluetooth device name: IIoT_new_XXXX, where XXXX is the last 4 symbols of the chip ID
Setup WIFI SSID: ENAiKOON-Technik
Setup WIFI password: EN2020ik
After the first init the error log file could be downloaded to check if all onboard devices have been initialized.

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

WRITE_BUFFER_CHAR e471ffa4-bb98-4659-8048-ddac87168882 This characteristic is used for writing the parameters for ports and registers.
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.

List of additional read-only characteristics

Name UUID Description Datatype States
PROCESSOR_ID_CHAR 81f55256-7375-46e1-babb-2820442f87fb Characteristic, that returns processor ID hex string always will return only processor ID
CONFIG_NAME_CHAR bbb07e3f-4acf-47d2-8975-d6724136d89f Characteristic, that returns uploaded config file name string always will return only config file name, or "default.xml" in the case of no file uploaded
RTC_CHAR 6aa56c5d-b817-4f00-aa94-986ca2fad51d Current RTC time value long always will return the RTC value
MODEL_CHAR 0c69bd10-1bf6-4b03-91fa-2a4a970e4d06 Device hardware composition model int 0 - UNDEFINED; 1 - M1-P1; 2 - M1-T1; 3 - M2-G1; 4 - M2-L1; 5 - M2-M1; 6 - M2-O1; 7 - M2-O1; 8 - M2-T1; 9 - M3-M1; 10 - M4-G1; 11 - M4-M1;
WIFI_STATUS_CHAR efd6671b-4cb6-4e73-9c7c-a6ca257be05f WiFi status characteristic int 0 - disabled ; 1 - enabled, not connected; 2 - enabled, connected with Internet; 3 - enabled, connected without Internet; 4 - ; 5 - ; 6 - ; 7 - ; 8 - ; 9 - ; 10 - ; 11 - ;
LORA_STATUS_CHAR 6c8885ed-ffe6-49cf-a833-059a88349a2b LoRA status characteristic int 0 - module soldered, but disabled; 1 - module enabled; 2 - module not present on a board;
GPRS_STATUS_CHAR 2303e8e4-a3c2-4ad8-a52c-0a3d34abb8f4 GPRS modem status characteristic int 0 - module soldered, but disabled; 1 - module enabled; 2 - module enabled and connected; 3 - module not present on a board;
GNSS_STATUS_CHAR 8c2aa6a9-7b70-4316-b9e2-fe9236e5f56c GNSS module status characteristic int 0 - module soldered, but disabled; 1 - module enabled; 2 - module enabled and fix established; 3 - module not present on a board;
BATTERY_STATUS_CHAR 4a220af6-fe9d-4270-9e53-43dac0e2dc03 Battery voltage characteristics int Battery voltage level, integer, 2 bytes. To get float value in Volts, the value must be divided by 100
BUTTON_STATE_CHAR f450abd4-9d37-4090-9723-3ce2a6683cff Button state characteristics int Integer, one byte, 0 - not pushed; 1 - pushed
TEMPERATURE_CHAR c1e8de51-1c5e-4789-9061-0b312e284b0f Temperature sensor value float Temperature sensor value in Celsius (by default)

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 will use the same MAIN_SERVICE uncial UUIDs, the scan result will 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 must 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 will 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 will store the timestamp value in UNIX format when character value will 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 will 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 (power management group A)
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 Analogue read ports for onboard measurements Input only
CAP_VOLTAGE Voltage of the discharging capacitor
GSM_BUS_VOLTAGE Voltage of the GSM module power supply bus
PRIMARY_BUS_VOLTAGE Voltage of the primary power line, supplied from the main 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 must be used with an inversion flag. Other devices can be activated by HIGH level (logic 1).

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 Return data type
GETSERIAL_COMMAND R@SR; The command used to request the serial number string
GETHASH_COMMAND R@HS; The command used to request the current CRC32 hash of the stored configuration file string
GETAPIKEY_COMMAND R@API; The command used to request the assigned API key from a memory string
SETAPIKEY_COMMAND W@API%<api-key> The command used to set the API key into a non-volatile memory string, "true" on success, "false" on error
GETPROCID_COMMAND R@PID; The command used to request the processor ID string
GETNAME_COMMAND R@NM; The command used to request the assigned device name from a memory string
GETCONFIG_COMMAND R@CF; The command used to request the configuration file string, chunked on 20 bytes pieces
SETCONFIG_COMMAND W@CF; The command used to initiate the configuration file uploading string, "true" on success, "false" on error
GETERRORS_COMMAND R@ER; The command used to request the error logs string, chunked on 20 bytes pieces
IDENTIFY_COMMAND W@BL; The command used to init the led blinking string, "true" on success, "false" on error
GETPORT_COMMAND R@PR%<N>; The command used in port reading requests, N equals to Integer, belonged to the appropriate port enumeration 0 or 2 decimal places, depending on port's type
SETPORT_COMMAND W@PR; The command used in a port writing workflow before the data will be written to WRITE_BUFFER_CHAR string, "true" on success, "false" on error
GETREG_COMMAND R@RG%<key>; The command used in register reading requests, <key> equals to String name of the requested register depends on stored register type (integer, unsigned integer, unsigned long, float, boolean, string)
SETREG_COMMAND W@RG%<data_type>@<key>;<value> The command used in a register writing workflow before the data will be written to WRITE_BUFFER_CHAR. Datatypes could be "I" - 32 bit integer, "F" - float, "S" - string, "B" - boolean, which has to receive value either 0 or 1. To set the configuration file filename should be used next command "W@RG%S@conf_name;configuration_file.xml". The 'key' parameter has 15 characters length limit. string, "true" on success, "false" on error
RESET_FS W@FMT; The command is used for the device's memory reset. string, "true" on success, "false" on error
FIRMWARE_UPDATE W@FUPD; The command is used for firmware updating using OTA. string, "true" on command applying success, "false" on error
SLEEP_CONFIG W@SLP; The command is used for pulling the device to configuration waiting mode. After the command execution, the device will go to deep sleep mode and could be turned back to configuration mode by PIR sensor or button triggerring. string, "true" on command applying success, "false" on error
OPERATION_MODE W@OPM; The command is used for switching the device to operational mode. In this mode, the device will work based on the configuration file with turned-off Bluetooth. To pull the device back to configuration mode, one of the following actions must be performed: 1 - connect and disconnect power supply 4 times with interval less than 10 seconds; Use the button patern string, "true" on command applying success, "false" on error

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 read with help of IIoT class method readPortDirect(PORT_REG port, PORT_READ_TYPE readType), where readType describes the data to be returned.
If readType is DISCRETE, the returning value will 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 will 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) must be used, where key is the value to be read.

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 can be used as follows:

IIoT_device.writeRegisterDirect("temp1", 23.4);

Helper methods

Getting the device's name

To get the device name stored in the non-volatile memory, the getDeviceName() method is used.
After calling

IIoT_device.getDeviceName();

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

Work with API-KEY

To send the API-KEY and save it inside the non-volatile device’s memory, the setApiKey(String apiKey) method is used.
After calling

IIoT_device.setApiKey(String apiKey);

The attached device will store the API-KEY

To get the API-KEY stored in the device’s memory, the getApiKey() method is used.
After calling

IIoT_device.getApiKey();

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

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

To get the device status variables, the direct reading from characteristics listed in the GATT structure is used

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 Configurable multiplexed ports outputs
MUXOUT_2_PORT 14
MUXOUT_3_PORT 15
MUXOUT_4_PORT 16
MUXOUT_5_PORT 17
MUXIN_1_PORT 18 Configurable multiplexed ports inputs
MUXIN_2_PORT 19
MUXIN_3_PORT 20
MUXIN_4_PORT 21
MUXIN_5_PORT 22
MUXIN_6_PORT 23
MUXIN_7_PORT 24
MUXIN_8_PORT 25
PINPORT_1_PORT 26 Configurable physical pins
PINPORT_2_PORT 27
PINPORT_3_PORT 28
PINPORT_4_PORT 29
PINPORT_5_PORT 30
PINPORT_6_PORT 31
PINPORT_7_PORT 32
P_POWER_PORT 33
TEMPERATURE_IN 34
CAP_VOLTAGE 35
GSM_BUS_VOLTAGE 36
PRIMARY_BUS_VOLTAGE 37

Methods

public boolean getSerialNumber()

Request the serial number

public boolean setApiKey(String apiKey)

Method for writing the API-KEY to the device's non-volatile memory

public boolean getApiKey()

Request the API-KEY saved in the device's non-volatile memory

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.