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

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

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.

Code generation inside of the project

To generate the code inside of the project, you can follow two instructions:

NixOS / Nix-enabled Linux

You have to open the Memory repository and type nix develop to get the required dependencies installed.

Then you simply run update_protobuf in the root of the Memory and new code should be generated

Windows / Other Linux distros

You have to clone the Memory repository.

You have to make sure you have Python 3.10 (or newer) installed, and Protobuf 27 (exactly) installed.

Then you simply run

Linux

protoc --plugin=protoc-gen-eams=protoc-gen-eams -I.. --eams_out=../generated communication.proto   

Windows

protoc --plugin=protoc-gen-eams=protoc-gen-eams.bat -I.. --eams_out=..\generated communication.proto   

in the root of the Memory and new code should be generated.

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 Centipede communication is the following:

syntax = "proto3";

syntax = "proto3";

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

message Project {
    UID project_id = 10;
    optional string client_code = 12;
    optional string site_code = 13;
    optional int32 last_update = 14;
    optional string project_name = 15;
}

message TestPlan {
    UID testplan_id = 20;
    string testplan_code = 21;
    string testplan_name = 22;
    bool locked = 23;
    repeated ResultSetting settings = 24;
    optional string description = 25;
    int32 lockPin = 26;
}

message Step {
    UID step_id = 30;
    UID parent_id = 31;
    int32 seq_num = 32;
    repeated ResultSetting results = 33;
    repeated Measurement measurements = 34;
    repeated ResultSetting settings = 35;
    optional string instruction = 36;
}

message Measurement {
    int32 measurement_number = 40;
    repeated ResultSetting results = 41;
    repeated ResultSetting settings = 42;
    optional int32 text_id = 43;
}

message DUT {
    UID dut_id = 50;
    string dut_code_or_serial = 51;
    optional UID project_id = 52;
    optional UID testplan_id = 53;
    repeated ResultSetting results = 54;
    optional int32 last_update = 55;
    optional string model_or_vin = 56;
    optional string plate_number = 57;
    optional string manufacturer = 58;
    repeated ResultSetting settings = 59;
    optional int32 ampacity_override = 60;
    optional int32 cable_length = 61;
    optional int32 phases_override = 62;
}

message ResultSetting {
    int32 name_enum = 60;
    optional ResultSettingValue value = 61;
    optional LimitValue limit = 62;
}

message ResultSettingValue {
    optional float numeric_value = 70;
    optional int32 descriptive_value = 71;
}

message LimitValue {
    optional float limit_low = 80;
    optional float limit_high = 81;
}

message Ota {
    int32 seq_num = 90;
    int32 address = 91;
    bytes byte_array = 92;
}

message UID {
    uint32 serial_counter = 100;
    uint32 timestamp = 101;
}

message TesterInfo {
    string fw_ver = 110;
    string hw_ver = 111;
    int32 protocol_version = 112;
    string ag_version = 113;
    int32 serial_number = 114;
    string model = 115;
    int32 last_calibration_date = 116;
    int32 communication_line = 117;
}

message OtaInfo {
    int32 number_of_packets = 120;
    int32 overall_crc32 = 121;
    string firmware_version = 122;
}

message UpdatePacket {
    OtaInfo info = 130;
    repeated Ota packets = 131;
}

message ImportExportCommand {
    optional int32 parameter = 140;
    repeated UID path_sections = 141;
    optional int32 seq_num = 142;
    optional bytes query = 143;
}

message DateTimeZoneCommand {
    int32 timezone = 150;
    int64 epoch = 151;
}

message CommandEnums {
    int32 Ota = 100;
    int32 Ok = 101;
    int32 Nok = 102;
    int32 TesterInfo = 103;
    int32 Import = 104;
    int32 Export = 105;
    int32 End = 106;
}

message ParameterOtaEnums {
    int32 Start = 108;
    int32 OtaErase = 109;
    int32 ShowUpdatePopup = 110;
    int32 CreateBridge = 111;
    int32 DestroyBridge = 112;
    int32 GoToBootloader = 113;
    int32 GoToApp = 114;
}

message ParameterEntityEnums {
    int32 Project = 111;
    int32 DUT = 112;
    int32 DUTStep = 113;
    int32 TestPlan = 114;
    int32 TestPlanStep = 115;
    int32 Root = 116;
    int32 TestPlanRoot = 117;
    int32 Manufacturer = 118;
    int32 VisualText = 119;
}

message StructureIDs {
    int32 Command = 10;
    int32 Project = 11;
    int32 DUT = 12;
    int32 DutStep = 13;
    int32 TestPlan = 14;
    int32 TestPlanStep = 15;
    int32 Result = 16;
    int32 Setting = 17;
    int32 Ota = 18;
    int32 TesterInfo = 19;
    int32 OtaInfo = 20;
    int32 ImportCommand = 21;
    int32 ExportCommand = 22;
    int32 DateTimeZoneCommand = 23;
    int32 Manufacturer = 24;
    int32 VisualText = 25;
}

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
Project codestring
Client codestring
Site codestring
Time of last updateint32?

Test Plan

Test plan is a top-level structure, which defines a testing procedure.

FieldType
TestPlan IDUID
TestPlan codestring
TestPlan namestring
Settings[ResultSetting]
Descriptionstring?

Step

Step is a structure that holds results, measurements, settings, instructions and sequence number. It can be found in both Test Plans and Workspaces.

FieldType
Step IDUID
Parent IDUID
Sequence numberint32
Results[ResultSetting]
Measurements[Measurement]
Settings[ResultSetting]
Instructionstring?

Measurement

Measurement holds a measurement number, results and settings.

FieldType
Measurement numberint32
Results[ResultSetting]
Settings[ResultSetting]

DUT

Dut structure represents the device under test.

FieldType
DUT IDUID
DUT Codestring
Project IDUID
Testplan IDUID?
Results[ResultSetting]
Last updateint32?

ResultSetting

ResultSetting is a structure that holds values common to both Result and Setting.

FieldType
Name enumint32
ValueResultSettingValue?
LimitLimitValue?

ResultSettingValue

ResultSettingValue stores either Numeric or Descriptive values.

FieldType
Numeric valuefloat?
Descriptive valueint32?

LimitValue

LimitValue stores the low and high values of the limit.

FieldType
Limit lowfloat?
Limit highfloat?

Export procedure

Export is done using the ExportCommand structure from the previous chapter.

When executing, the Command structure's fields represent the following:

FieldMeaning
CommandAlways set to Export
ParameterType being exported (Project, Station, Test, Measurement, Graph, Result)
Parameter2Parent UID, empty if the Parameter is set to Project

When exporting process has produced all items that fit the specified filter, the End command is sent.

Exported data

When the data is in the process of being exported, every export item is preceeded by an ImportExportCommand protobuf, which contains the data about the UIDs, which can then be used to generate a path on the filesystem.

The ImportExportCommand also contains some flags, which can give us some additional information.

Command

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

FieldType
Commandint32
Parameterint32?
Filterstring?

Command field

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

EnumValue
Ota100
Ok101
Nok102
TesterInfo103
Import104
Export105
End106
DateTime107

Parameter field

The parameter field can contain an enum from the below table

EnumValue
Start108
OtaErase109
ShowUpdatePopup110
Project111
DUT112
DUTStep113
TestPlan114
TestPlanStep115

Folder field

The parameter field can contain an enum from the below table

EnumValue
CUSTOM TESTPLAN116
FACTORY TESTPLAN117
USED TESTPLAN118

Filter field

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

ImportExport command

The ImportExportCommand is a structure that contains path to the information it wants to import/export and a property that explains what type you're looking for. ImportExportCommand is also used as a precursor before the exported item, so that we know where to store the data that follows it.

FieldType
Parameterint32?
Folderint32?
Path sections[UID]

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

Text formats

Texts

TextLengthUniqueAllowed characters
Various codes20YESNumeric
Various names20NOFW_ALL
Instruction1000 (bytes)NOFW_ALL
Description1000 (bytes)NOFW_ALL
All other text5000 (bytes)NOALL

Allowed characters

Numeric

  • 0-9

Code 39

  • A-Z
  • 0-9
  • - . $ / + %
  • space

File name characters

All except <>:"/\|?*

FW_ALL valid characters

UNICODESIGN
\u0020<space>
\u0021!
\u0022"
\u0024$
\u0025%
\u0027'
\u0028(
\u0029)
\u002a*
\u002b+
\u002c,
\u002d-
\u002e.
\u002f/
\u00300
\u00311
\u00322
\u00333
\u00344
\u00355
\u00366
\u00377
\u00388
\u00399
\u003a:
\u003b;
\u003c<
\u003d=
\u003e>
\u003f?
\u0040@
\u0041A
\u0042B
\u0043C
\u0044D
\u0045E
\u0046F
\u0047G
\u0048H
\u0049I
\u004aJ
\u004bK
\u004cL
\u004dM
\u004eN
\u004fO
\u0050P
\u0051Q
\u0052R
\u0053S
\u0054T
\u0055U
\u0056V
\u0057W
\u0058X
\u0059Y
\u005aZ
\u005b[
\u005c\
\u005d]
\u005e^
\u005f_
\u0060`
\u0061a
\u0062b
\u0063c
\u0064d
\u0065e
\u0066f
\u0067g
\u0068h
\u0069i
\u006aj
\u006bk
\u006cl
\u006dm
\u006en
\u006fo
\u0070p
\u0071q
\u0072r
\u0073s
\u0074t
\u0075u
\u0076v
\u0077w
\u0078x
\u0079y
\u007az
\u007e~
\u00a0<nbsp>
\u00a1¡
\u00a2¢
\u00a3£
\u00a5¥
\u00ad<soft-hyphen>
\u00b0°
\u00b1±
\u00b9¹
\u00b2²
\u00b3³
\u00b4´
\u00b5µ
\u00bf¿
\u00c0À
\u00c1Á
\u00c2Â
\u00c3Ã
\u00c4Ä
\u00c5Å
\u00c6Æ
\u00c7Ç
\u00c8È
\u00c9É
\u00caÊ
\u00cbË
\u00ccÌ
\u00cdÍ
\u00ceÎ
\u00cfÏ
\u00d0Ð
\u00d1Ñ
\u00d2Ò
\u00d3Ó
\u00d4Ô
\u00d5Õ
\u00d6Ö
\u00d7×
\u00d8Ø
\u00d9Ù
\u00daÚ
\u00dbÛ
\u00dcÜ
\u00ddÝ
\u00deÞ
\u00dfß
\u00e0à
\u00e1á
\u00e2â
\u00e3ã
\u00e4ä
\u00e5å
\u00e6æ
\u00e7ç
\u00e8è
\u00e9é
\u00eaê
\u00ebë
\u00ecì
\u00edí
\u00eeî
\u00efï
\u00f0ð
\u00f1ñ
\u00f2ò
\u00f3ó
\u00f4ô
\u00f5õ
\u00f6ö
\u00f7÷
\u00f8ø
\u00f9ù
\u00faú
\u00fbû
\u00fcü
\u00fdý
\u00feþ
\u00ffÿ
\u0106Ć
\u0107ć
\u011eĞ
\u011fğ
\u0130İ
\u0131ı
\u0141Ł
\u0142ł
\u0152Œ
\u0153œ
\u015eŞ
\u015fş
\u0178Ÿ
\u0192ƒ
\u03a9Ω
\u03c0π
\u2030
\u2212
\u2264
\u2265

Copiable format

[0x0020,0x0021,0x0022,0x0024,0x0025,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007e,0x00a0,0x00a1,0x00a2,0x00a3,0x00a5,0x00ad,0x00b0,0x00b1,0x00b9,0x00b2,0x00b3,0x00b4,0x00b5,0x00bf,0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff,0x0106,0x0107,0x011e,0x011f,0x0130,0x0131,0x0141,0x0142,0x0152,0x0153,0x015e,0x015f,0x0178,0x0192,0x03a9,0x03c0,0x2030,0x2212,0x2264,0x2265]
[\u0020\u0021\u0022\u0024\u0025\u0027\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u005b\u005c\u005d\u005e\u005f\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u007e\u00a0\u00a1\u00a2\u00a3\u00a5\u00ad\u00b0\u00b1\u00b9\u00b2\u00b3\u00b4\u00b5\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff\u0106\u0107\u011e\u011f\u0130\u0131\u0141\u0142\u0152\u0153\u015e\u015f\u0178\u0192\u03a9\u03c0\u2030\u2212\u2264\u2265]