Transport protocol

The data between the PC and STM is Protobuf preceeded by a 7-byte header and 5+n byte header.

The header itself consists of the following bytes:

DescriptionAmount of bytesValue
Start bytes10x2
Sender receiver10x0*
Message ID10x0
Size of content2number of bytes in content
Checksum of content1checksum of content (everything after 7th byte)
Checksum of header1checksum of header (first 6 bytes, skipping the leading 0x2)

Sender receiver

The sender-receiver value is documented as follows

Enums

ValueDescription
PC0
nRF1
STM2
STM - Memory3

Left 4 bits represent a sender Right 4 bits represent a recipient

STM - Memory has been separated for memory operations (Import, Export), due to ease of implementation.

The content consists of the following bytes:

DescriptionAmount of bytesValue
Protobuf Structure ID2Structure ID
Type112
Size of Protobuf content2number of bytes in the Protobuf content
Protobuf contentnThe Protobuf content that's being sent

Checksum

The message checksum is calculated by summing all bytes together and overflowing at a byte (sum % 256).

Structure ID

These structures are connected to the ones accessible here.

StructureID
Command0x10
Project0x11
Station0x12
Test0x13
Measurement0x14
RESERVED0x15
Result0x16
Setting0x17
Ota0x18
TesterInfo0x19
OtaInfo0x20
ExportCommand0x21
ImportCommand0x22

Communication enums

To include the communication enums starting with C_G_ into your own project, you can visit our public repository for them.

Then simply include the files and use them.

Fixed enums

There are a few enums that are fixed and aren't generated

OTA

Commands

enumnumber
OTA100

Parameters

enumnumber
Init101
OtaErase102
ShowUpdatePopup103
ShowTransferInProgressPopup104
ShowTransferCompletedPopup105

Responses

enumnumber
OK150
N_OK151

Tester info

Commands

enumnumber
TesterInfo200

End

Commands

enumnumber
End400

Import/Export

Commands

enumnumber
Import300
Export301

Parameters

enumnumber
Project350
Station351
Test352
Measurement353

Communication

The communication is based on Google's Protocol Buffer protocol, which generates code at build time.

The protocol schema is defined inside of a schema (*.proto) file, which is used to statically generate code and structures needed to serialize and deserialize bytes.

CLI Tool

ProtoBuf provides a CLI tool, called protoc, which can be used to generate the code and inspect the generated packets.

Code generation

To generate the code using the protoc tool, you will first need a schema.

Schema

A simple schema can be something like this:

message Example {
    int32 id = 1;
}

Which would, after the code generation, create an object that contains a single varint.

Code generation

To generate the code from the above schema, you will have to save it into a file, for this example test.proto, and run:

$ mkdir csharp
$ protoc test.proto --csharp_out=csharp/

Which should result in a new file, located at csharp/Test.cs, with code that can serialize and deserialize packets.

Printing binary contents

To figure out what is in the binary file generated from the program, you can use the following command:

$ protoc --decode Test --proto_path=. test.proto < test.bin

Which should result in:

id: 1

Schema

The schema that's used in the Hamilton communication is the following:

syntax = "proto3";

message Command {
    int32 command = 1;
    optional int32 parameter = 2;
    optional string filter = 3;
}

message Project {
    UID project_id = 10;
    int32 seq_num = 11;
    int32 client_code = 12;
    int32 site_code = 13;
    repeated Result results = 14;
    optional int32 last_update = 15;
    optional string name = 16;
}

message Station {
    UID station_id = 20;
    int32 seq_num = 21;
    repeated Setting settings = 22;
    UID project_id = 23;
    repeated Result results = 24;
    float earth_bond_limit_connection_point_1 = 25;
    optional float earth_bond_limit_connection_point_2 = 26;
    repeated float earth_bond_limit_test_point = 27;
    optional int32 last_update = 28;
    repeated int32 mfts_used = 29;
    bool marked_for_deletion = 30;
    optional float loop_line_limit = 31;
    optional string name = 32;
}

message Test {
    UID test_id = 30;
    int32 test_type = 31;
    int32 station_part = 32;
    int32 last_update = 33;
    repeated Result results = 34;
    UID station_id = 35;
}

message Measurement {
    UID measurement_id = 40;
    repeated Setting settings = 41;
    repeated Result results = 42;
    optional Graph graph = 43;
    UID test_id = 44;
}

message Graph {
    bytes byte_array = 50;
}

message Result {
    int32 name_enum = 60;
    optional string limit_low = 61;
    optional string limit_high = 62;
    optional float raw_numeric_value = 63;
    optional int32 enum_value = 64;
    int32 evaluation = 65;
    optional int32 unit = 66;
    optional int32 user_forced_state = 67;
    optional string rendered_numeric_value = 68;
}

message Setting {
    int32 name_enum = 70;
    optional float float_value = 71;
    optional int32 enum_value = 72;
}

message Ota {
    int32 seq_num = 80;
    int32 address = 81;
    bytes byte_array = 82;
}

message UID {
    int32 serial_counter = 90;
    int32 timestamp = 91;
}

message TesterInfo {
    string fw_stm = 100;
    string fw_bt = 101;
    string protocol_version = 102;
    int32 serial_number = 103;
    string model = 104;
    int32 last_calibration_date = 105;
}

message OtaInfo {
    int32 number_of_packets = 110;
    int32 overall_crc32 = 111;
    string firmware_version = 112;
}

message UpdatePacket {
    OtaInfo info = 120;
    repeated Ota packets = 121;
}

message ExportCommand {
    int32 parameter = 130;
    optional UID project = 131;
    optional UID station = 132;
    optional UID test = 133;
    optional UID measurement = 134;
}

message ImportCommand {
    int32 parameter = 130;
    optional UID project = 131;
    optional UID station = 132;
    optional UID test = 133;
    optional UID measurement = 134;
}

Database entries

The database consists of different tables, which connect with one to many relations. The relations are specified using a "parent id" on the children elements.

UID

UID is a structure storing instrument serial number and a timestamp, thus providing a unique identifier

FieldType
instrument_serialint32
timestampint32

The instrument_serial field doesn't use first 5 bits, so we use them as a counter. The counter helps us when data is saved multiple times in a single second.

The timestamp field is in seconds since EPOCH (01-01-1970).

Project

Project is a top-level structure, which stores a name and code.

FieldType
Project IDUID
Sequence numberint32
Client codeint32
Site codeint32
Results[Result]
Time of last updateint32

Station

Station is a structure that specifies the station being tested.

FieldType
Station IDUID
Sequence numberint32
Settings[Setting]
Project IDUID
Results[Result]
Earth bond limit connection point 1float
Earth bond limit connection point 2optional float
Earth bond limit test points[float]
Time of last updateint32
MFTs used[int32]
Marked for deletionbool

Test

Test is a structure that specifies a group of measurements that can be repeated.

FieldType
Test IDUID
Test typeint32
Station partint32
Time of last updateint32
Results[Result]
Station IDUID

Measurement

Measurement is a structure that contains Results.

FieldType
Measurement IDUID
Settings[Setting]
Results[Result]
Graphoptional Graph
Test IDUID

Graph

Graph is a structure that holds bytes that can be shown inside of the graph widget on the Hamilton.

FieldType
Byte_Arraybyte_array

Result

Result is a structure that holds a value, limit and evaluation of the result. Value can be an integer, float or an enum, so it's returned as a string.

FieldType
Name enumint32
Limitoptional string
Numeric valueoptional string
Enum valueoptional int32
Evaluationint32
Unitoptional int32
User forced stateoptional int32

Setting

FieldType
Name enumint32
Numeric valueoptional string
Enum valueoptional int32

Command

The command structure is made of multiple parameters, of which only one is mandatory.

FieldTypeOptional
Commandint32FALSE
Parameterint32TRUE
FilterstringTRUE

Command field

The command field can contain an enum from the below table.

EnumValue
Ota100
Ok150
Nok151
TesterInfo200
Import300
Export301
End400
DateTime500

Parameter field

The parameter field can contain an enum from the below table

EnumValue
Start101
OtaErase102
ShowUpdatePopup103
ShowTransferInProgressPopup104
ShowTransferCompletedPopup105
Project350
Station351
Test352
Measurement353

Filter field

The filter field can be a UNIX time integer to set the Hamilton time using DateTime command.

Export command

The ExportCommand is a structure that contains path to the information it wants to export and a property that explains what type you're looking for.

FieldType
parameterint32
projectUID
stationUID
testUID
measurementUID

Import command

The ImportCommand is a structure that contains path to the information it wants to import and a property that explains what type you're looking for. It needs to include the UID of the imported object

FieldType
parameterint32
projectUID
stationUID
testUID
measurementUID

Ota message

Ota is a structure that holds values needed for OTA update.

FieldType
sequence numberint32
addressint32
byte_arraybyte_array

Tester info

Tester info is the response to command TesterInfo.

FieldType
Firmware STMstring
Firmware nRFstring
Protocol versionstring
Serial numberint32
Modelstring
Last calibration dateint32

OtaInfo message

OtaInfo is a structure that holds values needed for OTA update.

FieldType
number of packetsint32
overall crc32int32
firmware_versionstring

OTA Update

STM Update

STM can update itself through OTA. It will flash itself through IAP and after verifying the flashed data, it will restart into the new application.

OTA has a few communication enums that can be passed into the Command message:

CommandParameterDescription
OtaOtaEraseErases the flash and prepares for flashing
OtaShowUpdatePopupShows the update popup that notifies the user that an update is underway
OtaStartTells the instrument that the update will follow

OtaErase should be sent if the instrument returned 0 in the Ok after the OtaInfo packet. If there are some packets present on the instrument, we should skip that many packets and continue from where it was last.

ShowUpdatePopup should be sent before a device starts updating and should be sent for both nRF and STM updates. The popup hides when the End is sent at the end of update.

OtaInfo contains a field overall_crc32, which should be compared with the last update that was done, so that we can track if there are some packets of this update already present or not.

OTA has a message called OTA with three fields:

FieldDescription
seq_numNumber of the packet in the update procedure
addressThe location the bytes will be written to
byte_arrayThe bytes to be written

OTAInfo has a message called OTAInfo with three fields:

FieldDescription
number_of_packetsNumber of all packets in the update procedure
overall_crc32CRC32 calculated over the whole binary
firmware_versionVersion of the new firmware

OTA also reuses the global End command:

CommandParameterDescription
EndFinish the update

After the End command is sent, the STM verifies the flashed parts of the flash, switches to the new application and reboots.

If the overall checksum doesn't match, it returns N_OK and shows a popup, otherwise it returns OK and reboots.

Replies

Commands OtaErase, Start and End will reply with OK or N_OK commands depending on the status of the command that was executed last.

STM Update procedure

STM Update procedure

nRF Communication

The nRF communication for transferring data contains a service with UID 0x1000 which contains two characteristics:

CharacteristicID
Write0x6000
Notification0x7000

The data received and sent on these characteristics, is in Protobuf protocol.

nRF Commands

The nRF communication protocol defines commands

CommandsValueDescriptionDirection (to)
C_G_PAIRtrue/falseStart/stop pairing process on nRF.nRF
C_G_PAIREDSerial number of MFTReturns when the MFT has been paired.STM
C_G_CONNECTEDNo valueReturns when the MFT has connected.STM
C_G_DISCONNECTEDNo valueReturns when the MFT has disconnected.STM
C_G_ROLERole valuesChange the Bluetooth role.nRF
C_G_MACMAC addressProvides the MAC address of the bonded deviceboth
C_G_FIRMWAREThe version of nRFReturns the FW version of nRF (eg. "00.65")STM
C_G_EXPORT_BUFFERS_READYNo valueTells STM that the Export buffers are ready to receive dataSTM
  • The C_G_MAC should always be sent with the C_G_CENTRAL role command.
  • The C_G_MAC is also sent with C_G_PAIRED in the direction of STM.
  • The C_G_FIRMWARE is sent after the nRF and STM are handshaked.

Role values

Possible values for role:

ValueDescription
C_G_IDLEPut nRF into idle, to conserve power
C_G_CENTRALPut nRF into MFT connectivity mode
C_G_PERIPHERALPut nRF into PC connectivity mode

MFT Communication

Communication is through common_com_lib, which allows us to add multiple items and specify key-value entries.

MFT Schema

mft schema

Commands

The MFT communication protocol defines 4 MFT commands

CommandsValueDescription
C_G_EVENT_ENTEREnter valuesEnter into the measurement
C_G_EVENT_STARTStart valuesStart sending the results
C_G_EVENT_STOPNo valueStop sending the results
C_G_EVENT_EXITNo valueExit from the measurement

Enter values

C_G_EVENT_ENTER command has to specify the measurement we want to enter.

Possible values for Earth Bond measurement:

ValueDescription
C_EARTH_BOND_MEASUREMENT_RPEEarth bond measurement

Possible values for Insulation measurement:

ValueDescription
C_LOOP_LINE_MEASUREMENT_LN_MEASVoltage measurement between L1 and N
C_LOOP_LINE_MEASUREMENT_LPE_MEASVoltage measurement between L1 and PE
C_LOOP_LINE_MEASUREMENT_NPE_MEASVoltage measurement between N and PE

Possible values for Line measurement:

ValueDescription
C_LOOP_LINE_MEASUREMENT_LN_MEASVoltage measurement between L1 and N
C_LOOP_LINE_MEASUREMENT_LPE_MEASVoltage measurement between L1 and PE

Start values

C_G_EVENT_START command has to specify the measurement we want to enter. Values are the same as they are for C_G_EVENT_ENTER.

Settings

There are 5 different settings that can be set.

Rotary values

Rotary tells us which measurement is selected on MFT using rotary selector.

ValueDescription
C_SETTINGS_GLOBAL_SETT_VAL_MFT_ROTARY_INSULATIONInsulation measurement is selected
C_SETTINGS_GLOBAL_SETT_VAL_MFT_ROTARY_CONTINUITYContinuity measurement is selected
C_SETTINGS_GLOBAL_SETT_VAL_MFT_ROTARY_LINE_NO_TRIPLine no trip measurement is selected
C_SETTINGS_GLOBAL_SETT_VAL_MFT_ROTARY_NANone of the above measurements is selected

F1 values

Possible values for the F1 setting.

ValueDescription
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_LNMeasurement between L and N sockets
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_LPEMeasurement between L and PE sockets
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_NPEMeasurement between N and PE sockets
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_NAF1 is set to none of the above

F2 values

Possible values for the F2 setting.

ValueDescription
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F2_ZEROEDThe result value had been zeroed already
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F2_NAF2 is set to none of the above

F3 values

Possible values for the F3 setting.

ValueDescription
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_PRETEST_OFF
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_PRETEST_OHM_PLUS_MINUS
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_Z_MAX_OFF
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_NAF3 is set to none of the above

F4 values

Possible values for the F4 setting.

ValueDescription
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F4_MA250
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F4_V500
C_SETTINGS_GLOBAL_SETT_VAL_MFT_F4_NAF4 is set to none of the above

Results

Results are always of type FLOAT. The message sent over the communication, should consist of keys specified below, according to the measurement, and value, which will always be a float.

RPE Earth bond

RPE Earth bond only has one result.

Result
C_EARTH_BOND_RES_RPE_EARTH_BOND

Insulation

Insulation contains 6 results.

Result
C_INSULATION_RES_RLN_INSULATION
C_INSULATION_RES_ULN_INSULATION
C_INSULATION_RES_RLPE_INSULATION
C_INSULATION_RES_ULPE_INSULATION
C_INSULATION_RES_RNPE_INSULATION
C_INSULATION_RES_UNPE_INSULATION

Line

Line measurement contains 4 results.

Result
C_LOOP_LINE_RES_ZLN_LINE
C_LOOP_LINE_RES_ILN_LINE
C_LOOP_LINE_RES_ZLPE_LINE
C_LOOP_LINE_RES_ILPE_LINE

Measurement procedure

Measurement procedure

The measurement procedure is as follows:

  • Selection of the measurement using Enter
    • After the Enter is called, the MFT settings will be sent to the STM initially and after a change.
  • Start of the result sending using Start
    • After the Start is called, the MFT results will be sent to the STM every n milliseconds.
    • If we're still in Enter, settings can still be received if they change.
  • Stop the sending of results using Stop
  • Exit the measurement using Exit

Example

The following is an example of how the communication should be executed. The packets will be in JSON for readability, but should be in the common_com_lib packets in practice.

  1. Send an ENTER command with C_EARTH_BOND_MEASUREMENT_RPE measurement.

STM -> nRF1

{
  "items": [
    {
      "key": "C_G_EVENT_ENTER",
      "value": "C_EARTH_BOND_MEASUREMENT_RPE"
    }
  ]
}
  1. The nRF should start sending back current MFT's settings, preferrably when their value has changed.

nRF -> STM2

{
  "items": [
    {
      "key": "C_G_FUNC_SETTINGS_GLOBAL"
    },
    {
      "key": "C_SETTINGS_GLOBAL_SETT_MFT_ROTARY",
      "value": "C_SETTINGS_GLOBAL_SETT_VAL_MFT_ROTARY_CONTINUITY"
    },
    {
      "key": "C_SETTINGS_GLOBAL_SETT_MFT_F1",
      "value": "C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_LN"
    },
    {
      "key": "C_SETTINGS_GLOBAL_SETT_MFT_F2",
      "value": "C_SETTINGS_GLOBAL_SETT_VAL_MFT_F2_ZEROED"
    },
    {
      "key": "C_SETTINGS_GLOBAL_SETT_MFT_F3",
      "value": "C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_PRETEST_OHM_PLUS_MINUS"
    },
    {
      "key": "C_SETTINGS_GLOBAL_SETT_MFT_F4",
      "value": "C_SETTINGS_GLOBAL_SETT_VAL_MFT_F4_MA250"
    }
  ]
}
  1. When the measurement on STM is started, the C_G_EVENT_START will be sent.

STM -> nRF3

{
  "items": [
    {
      "key": "C_G_EVENT_START",
      "value": "C_EARTH_BOND_MEASUREMENT_RPE"
    }
  ]
}
  1. The nRF should start sending back results when they're available, possibly waiting for the user to start the measurement.

nRF -> STM4

{
  "items": [
    {
      "key": "C_EARTH_BOND_MEASUREMENT_RPE"
    },
    {
      "key": "C_EARTH_BOND_RES_RPE_EARTH_BOND",
      "value": 0.25
    }
  ]
}
  1. The STM stops the measurement.

STM -> nRF5

{
  "items": [
    {
      "key": "C_G_EVENT_STOP",
      "value": null,
    }
  ]
}
  1. The STM exits the measurement.

STM -> nRF6

{
  "items": [
    {
      "key": "C_G_EVENT_EXIT",
      "value": null,
    }
  ]
}

Packets templates in C/C++

To create the packet, the following boilerplate can be used:

Enter packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_G_EVENT_ENTER, C_EARTH_BOND_MEASUREMENT_RPE);
MSG_SEND(&comm, msg);

Settings packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_G_FUNC_SETTINGS_GLOBAL);
MSG_APPEND(msg, C_SETTINGS_GLOBAL_SETT_MFT_ROTARY, C_SETTINGS_GLOBAL_SETT_VAL_ROTARY_INSULATION);
MSG_APPEND(msg, C_SETTINGS_GLOBAL_SETT_MFT_F1, C_SETTINGS_GLOBAL_SETT_VAL_MFT_F1_LN);
MSG_APPEND(msg, C_SETTINGS_GLOBAL_SETT_MFT_F2, C_SETTINGS_GLOBAL_SETT_VAL_MFT_F2_ZEROED);
MSG_APPEND(msg, C_SETTINGS_GLOBAL_SETT_MFT_F3, C_SETTINGS_GLOBAL_SETT_VAL_MFT_F3_PRETEST_OHM_PLUS_MINUS);
MSG_APPEND(msg, C_SETTINGS_GLOBAL_SETT_MFT_F4, C_SETTINGS_GLOBAL_SETT_VAL_MFT_F4_MA250);
MSG_SEND(&comm, msg);

Start packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_G_EVENT_START, C_EARTH_BOND_MEASUREMENT_RPE);
MSG_SEND(&comm, msg);

Result packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_EARTH_BOND_MEASUREMENT_RPE);
MSG_APPEND(msg, C_EARTH_BOND_RES_RPE_EARTH_BOND, 0.25);
MSG_SEND(&comm, msg);

Stop packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_G_EVENT_STOP);
MSG_SEND(&comm, msg);

Exit packet

MSG_CREATE(msg);
MSG_APPEND(msg, C_G_EVENT_EXIT);
MSG_SEND(&comm, msg);

Calibration

Calibration mode is used to calibrate the instrument and verify that the instrument works correctly.

Bluetooth specifications

To connect to the calibration part of the Hamilton, you need to connect to service with UUID 0x1337 that contains two characteristics:

CharacteristicID
Write0x3000
Notification0x5000

The calibration uses the calibration protocol defined here

Data processing

nRF forwards the data received as a string on the Write characteristic and forwards it as a packet with an item ID of 666 to the STM, where it gets processed.

When sending data, nRF receives a packet that contains only one item (with an id of 666), which contains a byte array (an array of ASCII characters), which gets extracted and forwarded through bluetooth notification.