Skip to main content
FW version: Stable

Firmware upgrade using IOT device

warning

Approximatelly from the new year 2025, the SRM endpoint will be changed. If you are using or implementing this protocol, please contact us and we will keep you informed about the changes in advance.

More info in Querying the SRM section.

This document describes how to perform a firmware upgrade using CAN and siliXcon’s SRM (server with firmware repository) for an external developer. It should be regarded as a simple guide allowing to embed the upgrade process into another system. The document doesn’t aim to describe the entire proprietary service protocol, just the selected parts that are necessary for the upgrade process.

Note for CAN bus

All the data in the CAN messages are encoded in little endian - INTEL format

Please ensure that the CAN bus and CAN timing are correctly set. Please do not mix CANH and CANL wires and ensure that the bus is properly terminated with a 120Ohm resistor. All CAN IDs described below are 11 bits.

The firmware size is around 250kb.

Legend

  • Host: the 3RD party system (to implement the upgrade process). Have address 7.
  • Device: A siliXcon product (display, device, BMS)
  • DNC: Do Not Care. This information can have an arbitrary value with no significance for the host.
  • SRM: Secure Remote Management (siliXcon’s server with firmware repository)
  • Service: a device‘s internal communication object with an independent context. (BL, ID, PWR)

Establishing dialog with the bootloader

First of all, the host needs to put the device into bootloader mode. This is done by resetting the device and sending the SELECT command, as described below.

1. Reset the device

Reset the device using the PWR/reboot command. This command will instruct all devices (or another siliXcon products on the CAN-bus) to reboot. It is necessary to reboot the device in order to establish communication with the bootloader.

Service / CommandDirectionCAN IDDLC
PWR / RebootHost -> Device01

Payload:

Byte 0
Target address

2. Wait for the ATR

Wait for the ATR (answer to reset). As a response to the REBOOT, the device sends a message called ATR (answer to reset). The host shall wait for this message to ensure the reset took place. If the ATR does not arrive (within a timeout of ~500ms), the host can attempt to reset the device once again. The first 3 bytes must contain the value specified in the table, all other bytes shall not be parsed. At most 3 attempts are recommended, before a failure shall be considered.

Service / CommandDirectionCAN IDDLC
BL / ATR responseDevice -> Host8*4 + device address
Usually 32 (device address 0)
8

Payload:

Byte 0Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7
0xFF (0x07 for Boootloader version older than 2022)0x400x00DNCDNCDNCDNCDNC
Host address (broadcast)RESET | RESPONSE indicationReset reason

3. Do a handshake by issuing the SELECT command.

The bootloader waits for about ~200ms after the ATR is sent, for the SELECT command. If the SELECT command is not received, the bootloader passes control to the main application.

Service / CommandDirectionCAN IDDLC
BL / SELECTHost -> Device8*4 + host address (7 is used as host address)
Usually 39 (host with address 7)
4

Payload:

Byte 0Byte 1Byte 2Byte 3
0x000x020x00Session ID (DNC)
Device addressSELECT commandDevice address repeatedX (device increments the X value with each new host‘s command)

4. Wait for the SELECT response

Wait for the SELECT response. The bootloader sends this message as a confirmation of successful selection (hand shaken back). If the host doesn’t receive the SELECT response or, the first three bytes contain other than specified values, the host can attempt to send the SELECT command again. At most 3 attempts are recommended, before a failure shall be considered.

Service / CommandDirectionCAN IDDLC
BL / SELECT responseDevice -> Host8*4 + device address
Usually 32 (device address 0)
3

Payload:

| Byte 0 | Byte 1 | Byte 2 | | ------------ | ------ | ------------------- | ----------------------- | | 0x00 | 0x42 | 0x00 | | Host address | SELECT | RESPONSE indication | Device address repeated |

Retrieving the identifiers

At this step, we assume that the communication with the bootloader was established up to the point where the SELECT response was successfully received.

Get device IDINFO

1. Request device IDINFO

Ask for the device’s IDINFO using the GETINFO command of the ID service. Now, the host shall issue the GETINFO command if the ID service retrieves the IDINFO. IDINFO is a set of string identifiers that the host must afterward send to the online SRM service.

Service / CommandDirectionCAN IDDLC
ID / GETINFOHost -> Device8*3 + host address (7 is used as host address)
Usually 31 (host with address 7)
3

Payload:

Byte 0Byte 1Byte 2
0x000x010x00
Device addressGETINFO command-

2. Receive IDINFO

Receive IDINFO data from the device. The device will respond with a series of messages to the GETINFO command. The host shall receive all these messages, collect the DATA in an input buffer and once transmission is finished, it should compute the CRC8 and check it against the CRC received in the footer message.

The IDINFO header message indicates the transfer start, contains the number of bytes the device will consequently send (dlen) and is transmitted once.

Header message:

Service / CommandDirectionCAN IDDLC
ID / GETINFO responseDevice -> Host8*3 + device address
Usually 24 (device address 0)
8
Byte 0Byte 1Byte 2Byte 3 - 6Byte 7
0x070x410x10 = successDlen LSB - Dlen MSBSession ID (DNC)
Host addressGETINFO / RESPONSE indicationCommand resultNumber of bytes to be transferred, UINT32_T (encoded in little endian)X (device increments the X value with each new host‘s command)

Data message

Service / CommandDirectionCAN IDDLC
ID / GETINFO response dataDevice -> Host8*3 + device address
Usually 24 (device address 0)
Max(8, remaining bytes to be transferred)
Byte 0Byte 1Byte 2 - 7
0x070x71Payload
Host addressGETINFO / DATA indicationThe payload (1 – 6 bytes per single message).

Footer message

The IDINFO footer message is transmitted at the end. It contains the 8-bit CRC of the transferred data. The CRC is computed from the entire data using the attached C-code. If there is a CRC mismatch, not all data were received or either the footer or header message is missing, the host can retry the transaction (by issuing the GETINFO command again).

Service / CommandDirectionCAN IDDLC
ID / GETINFO response footerDevice -> Host8*3 + device address
Usually 24 (device address 0)
5
Byte 0Byte 1Byte 2Byte 3Byte 4
0x070x510x00CRCSession ID (DNC)
Host addressGETINFO / CMDPART1
footer indication
The data payload (1 – 6 bytes per single message).The host should compute the CRC8 of the received data chunk and compare it against this value.X (device increments the X value with each new host‘s command)

3. Request device BLINFO

Ask for the device’s BLINFO using the GETINFO command of the BL service. Now, the host shall issue the GETINFO command of the BL service to retrieve the BLINFO. BLINFO is another set of string identifiers that the host must afterward send to the online SRM.

Service / CommandDirectionCAN IDDLC
BL / GETINFOHost -> Device8*4 + host address (7 is used as host address)
Usually 39 (host with address 7)
3

Payload:

Byte 0Byte 1Byte 2
0x000x030x00
Device addressBL GETINFO commandDNC

4. Receive BLINFO

Receive BLINFO data from the device. The device will respond with a series of messages to the GETINFO command. The host shall receive all these messages, collect the DATA in an input buffer and once transmission is finished, it should compute the CRC8 and check it against the CRC received in the footer message. Semantics is described below:

The BLINFO header message indicates the transfer start, contains the number of bytes the device will consequently send (dlen) and is transmitted once.

Header message:

Service / CommandDirectionCAN IDDLC
ID / GETINFO responseDevice -> Host8*4 + device address
Usually 32 (device address 0)
8
Byte 0Byte 1Byte 2Byte 3 - Byte 6Byte 7
0x070x430x10 = successDlen LSB - Dlen MSBSession ID (DNC)
Host addressGETINFO / RESPONSE indicationCommand resultNumber of bytes to be transferred, UINT32_T (encoded in little endian)X (device increments the X value with each new host‘s command)

Data message

Service / CommandDirectionCAN IDDLC
ID / GETINFO response dataDevice -> Host8*4 + device address
Usually 32 (device address 0)
Max(8, remaining bytes to be transferred)
Byte 0Byte 1Byte 2 - 7
0x070x73Payload
Host addressGETINFO / DATA indicationThe payload (1 – 6 bytes per single message).

Footer message

The BLINFO footer message is transmitted at the end. It contains the 8-bit CRC of the transferred data. The CRC is computed from the entire data using the attached C-code. If there is a CRC mismatch, not all data were received or either the footer or header message is missing, the host can retry the transaction (by issuing the GETINFO command again).

Service / CommandDirectionCAN IDDLC
ID / GETINFO response footerDevice -> Host8*4 + device address
Usually 32 (device address 0)
5
Byte 0Byte 1Byte 2Byte 3Byte 4
0x070x530x00CRCSession ID (DNC)
Host addressGETINFO / CMDPART1
footer indication
The data payload (1 – 6 bytes per single message).The host should compute the CRC8 of the received data chunk and compare it against this value.X (device increments the X value with each new host‘s command)

Querying the SRM

warning

This is documentation for new SRM server, that will be used from 2025. If you are using or implementing this protocol, please contact us and we will keep you informed about the changes in advance.

As a next step, once the IDINFO and BLINFO are successfully obtained, the host shall invoke the SRM with an UPGRADE query. The SRM is an online querying service that can be used (apart from other functionality) to retrieve the firmware upgrades.

The SRM service is a RESTful service that can be accessed via HTTPS. The host shall send a POST request to the SRM with the following payload (this is example data):

URL: Contact siliXcon support to get early access to the testing server. With the testing server you can test the API before it is released.

blinfo and idinfo are encoded using base64 encoding.

{
"query": "UPGRADE-nightly:VECTOR_LYNX_generic v6.0.0-nightly Nov 27 2024",
"tool": {
"name": "my_awesome_iot_device",
"version": "1.2.3"
},
"device": {
"idinfo": "MUE0MQBlc2MzLXNsMWtfNDhleGExMDYwLUMwMABTTC1zZXJwZW50AEVtQkwgIHYyLjUuMiBPY3QgIDIgMjAyMwAyMDM0MzAzODQzNTg1MzEzMDAyOTAwMzcAMEM6U0wA",
"blinfo": "MUE0OAA0MTBGQzI0MQA4MDAwADQwMDAwADEwMDAAN0FENjRCMTkAMjlFMTQAVkVDVE9SX09QSElPTl9nZW5lcmljIHY0LjMuMi10ZXN0aW5nIE9jdCAxNiAyMDI0AA=="
}
}
FieldDescription
querySRM query, More info.
toolInformation about the host system. It is optional, but it can help with debuging.
deviceidinfo and blinfo retrieved from the device, encoded using base64.
How to parse the idinfo and blinfo to get info about the device?

Using the following Python code, the idinfo and blinfo can be decoded nad parsed. This is not needed during the upgrade process, but it can be useful for debugging. If you succesfully decode the idinfo and blinfo, you can be sure that the data was correctly received from the device.


import base64
import pytest

def decode_and_split(enc):

enc = base64.b64decode(enc).decode("utf-8").split("\000")
return enc


def decodeBlInfo(blinfo_base64):
parts = decode_and_split(blinfo_base64)

blinfo = {
"magic": parts[0],
"cpuid": parts[1],
"blsize": parts[2],
"flashsize": parts[3],
"pagesize": parts[4],
"appmagic": parts[5],
"appsize": parts[6],
"swid": parts[7],
}

if blinfo["magic"] != "1A48":
raise ValueError("Invalid magic number")

return blinfo


def decodeIdInfo(idinfo_base64):
parts = decode_and_split(idinfo_base64)

idinfo = {
"magic": parts[0],
"hwid": parts[1],
"Basename": parts[2],
"swid": parts[3],
"uuid": parts[4],
"signature": parts[5],
}

if idinfo["magic"] != "1A41":
raise ValueError("Invalid magic number")

return idinfo

def test_decode_info():
# Test decodeIdInfo
test_idinfo_cases = [
{
"base64_data": "MUE0MQBlc2MzLXNsMWtfNDhleGExMDYwLUMwMABTTC1zZXJwZW50AEVtQkwgIHYyLjUuMiBPY3QgIDIgMjAyMwAyMDM0MzAzODQzNTg1MzEzMDAyOTAwMzcAMEM6U0wA",
"expected": {
"magic": "1A41",
"hwid": "esc3-sl1k_48exa1060-C00",
"Basename": "SL-serpent",
"swid": "EmBL v2.5.2 Oct 2 2023",
"uuid": "203430384358531300290037",
"signature": "0C:SL",
},
}
]

# Test decodeBLInfo
test_blinfo_cases = [
{
"base64_data": "MUE0OAA0MTBGQzI0MQA4MDAwADQwMDAwADEwMDAAN0FENjRCMTkAMjlFMTQAVkVDVE9SX09QSElPTl9nZW5lcmljIHY0LjMuMi10ZXN0aW5nIE9jdCAxNiAyMDI0AA==",
"expected": {
"magic": "1A48",
"cpuid": "410FC241",
"blsize": "8000",
"flashsize": "40000",
"pagesize": "1000",
"appmagic": "7AD64B19",
"appsize": "29E14",
"swid": "VECTOR_OPHION_generic v4.3.2-testing Oct 16 2024",
},
}
]

# Test all idinfo cases
for test_case in test_idinfo_cases:
result = decodeIdInfo(test_case["base64_data"])
expected = test_case["expected"]
for key in expected:
assert result[key] == expected[key], f"Failed on idinfo key {key}"

# Test all blinfo cases
for test_case in test_blinfo_cases:
result = decodeBlInfo(test_case["base64_data"])
expected = test_case["expected"]
for key in expected:
assert result[key] == expected[key], f"Failed on blinfo key {key}"

# Run tests if file is run directly
if __name__ == "__main__":
pytest.main([__file__])

Response

This is an example of the response from the SRM. The response contains the information about the upgrade availability and the secured load. The secured load is encrypted firmware that can be flashed to the device.

{
"query": "UPGRADE-nightly:VECTOR_LYNX_generic v6.0.0-nightly Nov 27 2024",
"server": "Odoo 17 Silixcon",
"current_rom": {
"swid": "VECTOR_LYNX_generic v6.0.0-nightly Nov 27 2024",
"release_type": "nightly",
"available_upgrade": false
},
"result": 0,
"string_result": "OK",
"secured_load": "MjlFMTQAVkV.............."
}

The secured_load is a base64 encoded string that contains the encrypted firmware. The host shall decode the secured_load to binnary format and flash it to the device.

Error response examples

TBD

Flashing the received payload to the device

During the flashing process, the host sends the secured_load as is to the device as payload. The device will decrypt the secured load and flash it to the internal memory.

2. Send LOAD command

Service / CommandDirectionCAN IDDLC
BL/LOADHost -> Device8*4 + host address (7)
Usually 39
8

Payload

Byte 0Byte 1Byte 2 - 5Byte 6-7
0x000x0EUINT32_T Litte endian0x015C
Device addressLoadTotal lenghtCrypto ID

Response:

Service / CommandDirectionCAN IDDLC
BL / LOADDevice -> host8*4 + host address (0 is used as host address)
Usually 31 (host with address 7)
7

Payload:

Byte 0Byte 1Byte 2Byte 3 - 7
0x000x4E0x10 = successChunk size
Host addressBL/LOAD responseCommand resultUINT32_T Litte endian

2.1 Send the firmware payload - SLOW method

Service / CommandDirectionCAN IDDLC
BL / LOADHost -> Device8*4 + host address (7 is used as host address)
Usually 39 (host with address 7)
8, or remaining bytes to be transferred

Payload:

Byte 0Byte 1Byte 2--7
0x000x3ETotal lenght of the payload
Device addressBL/LOAD DATA indicationPayload 0 - 5

2.2 Send the firmware payload - FAST method

Service / CommandDirectionCAN IDDLC
BL / LOADHost -> Device8*5 + host address (7 is used as host address)
Usually 47 (host with address 7)
8, or remaining bytes to be transferred

Payload:

Byte 0 - 7
Payload 0 - Payload 7

Footer messge:

The LOAD footer message is transmitted at the end of the chunk. It contains the 8-bit CRC of the transferred data. The CRC is computed from the entire data. If there is a CRC mismatch, not all data were received or either the footer or header message is missing, the host can retry to retransmit the data chunk.

Service / CommandDirectionCAN IDDLC
BL / LOADHost -> Device8*4 + host address (7 is used as host address)
Usually 39 (host with address 7)
3

Payload:

Byte 0Byte 1Byte 2
0x000x2ECRC8
Device addressBL/LOAD DATA footer indicationCRC of the transfered chunk

2.4 Receive ack

Service / CommandDirectionCAN IDDLC
BL / LOADDevice -> host8*4 + host address (0 is used as host address)
Usually 32 (host with address 0)
8

Payload:

Byte 0Byte 1Byte 2Byte 3 - 6Byte 7
0x070x4E
0x10 - send next chunk
0x00 - done
other - error
Next chunk sizeSession ID
Host addressBL/LOAD responseCommand resultUINT32_T Litte endianX

Exit bootloader

A Last step is necessary to exit the bootloader and enter the main program. To perform this step run command needs to be sent. After this, the device should be updated and prepared to work

warning

If the upgrade process is interrupted, or the internal CRC check of the whole FW is incorrect, the device stays in bootloader mode. In this case, it is necessary to repeat the whole process again.

Service / CommandDirectionCAN IDDLC
BL / RUNHost -> Device8*4 + host address (7 is used as host address)
Usually 39 (host with address 7)
2

Payload:

Byte 0Byte 1
0xFF0x01
Device address (broadcast)RUN command

Appendix

CRC8 computation

The CRC8 is computed using the following C-code:

static const uint8_t crc8_table[256] = {0x0, 0x7, 0xE, 0x9, 0x1C, 0x1B,
0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E,
0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4,
0xC3, 0xCA, 0xCD, 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF,
0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5,
0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE,
0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 0x27,
0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04,
0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61,
0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 0xF9, 0xFE, 0xF7, 0xF0, 0xE5,
0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E,
0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43,
0x44, 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28,
0x3D, 0x3A, 0x33, 0x34, 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76,
0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25,
0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0,
0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA,
0xFD, 0xF4, 0xF3
};


uint8_t
crc8(const uint8_t* ptr, int32_t len)
{
uint8_t crc = 0;
len++;

while (--len)
crc = crc8_table[crc ^ *ptr++];

return crc;
}

ACK and Commands results

The result is bitwise, i.e. there can be multiple results at once.

NameValueDescription
TCP_STE_DONE0x00
TCP_ERR_GENERIC0x08
TCP_ERR_WRONG_NBYTES0x09
TCP_ERR_NO_TRANSFER0x0A
TCP_ERR_CRC0x0B
TCP_ERR_CHUNK0x0C
TCP_ERR_ARB_LOST0x0D
TCP_ERR_SIZE0x0E
TCP_ERR_UNSUPPORT0x0F
TCP_STE_PENDING0x10
TCP_STE_EXPEDITED0x80