M2M: S-UDP protocol

Tato stránka popisuje funkci zařízení SDS druhé produktové řady - protože SDS první produktové řady používají jiný protokol.

Rychlá komunikace: S-UDP

Pomocí speciálního protokolu, kdy se data přenášejí prostřednictvím UDP, je možné získávat informace z výrobků řady SDS/OnlineTechnology.

S-UDP používá následující výchozí UDP PORT: 310

Komunikace probíhá formou DOTAZ - ODPOVĚĎ. To znamená, že ten, kdo má o informace zájem (vzdálený uživatel) pošle dotaz (korektně vyplněný UDP paket, viz dále) a obratem obdrží od zařízení odpověď - UDP paket s informacemi. UDP Port na kterém je komunikace prováděna lze samozřejmě v administraci zařízení změnit.

Přenos dat využívá specifického protokolu, který umožňuje bezpečně ovládat specifické zařízení SDS.


Typické použití: komunikace zařízení SDS s protistranou (např. aplikace na mobilním telefonu).


Bezpečnost

Protokol S-UDP je založen na důsledné autentizaci strany, která posílá zprávu - zařízení SDS ověřuje identitu odesílatele příkazu, a ten může ověřit identitu SDS který odpovídá.


Je to založeno na následujícím principu:

- S-UDP protokol je zabezpečen symetrickou šifrou, se sdíleným klíčem který znají jen komunikující strany (bezpečnost je přímo úměrná úrovni zabezpečení tohoto klíče na obou stranách)

- SDS má unikátní identifikátor (zaručeně unikátní, od výrobce) který nelze změnit (je fyzicky vypálen v SoC - nezměnitelně přímo v silikonu chipu).


S-UDP protokol

Každý příkaz a odpověď jsou v samostatném, jediném, UDP paketu.

Každý paket je sestaven v rámci společného formátu, který je zde popsán. Samotný doplňující datový obsah (payload) je dynamický, a u některých příkazů není potřeba.

S-UDP Paket se tedy skládá z těchto základní částí (tyto části jsou právě přenášeny UDP paketem, v následující sestavě):

 [MASTER PACKET CONTENTS]

  OFFSET    | LEN    |  DATA
  ----------+--------+---------------------------------------------------------------
    0       |     28 |  HEADER
   28       |  PL*16 |  ENCRYPTED PAYLOAD (contains: payload-header and payload-data)

Pozor! Hodnota PL je velikost [ENCRYPTED PAYLOAD] vydělená 16. To znamená, že velikost [ENCRYPTED PAYLOAD] musí být beze zbytku dělitelná 16 (tzn. pouze hodnota 16, 32, 64, ...) ! Pokud je potřeba, doplní se na úplný konec (viz oblast "R") zarovnání do potřebné délky, aby se dosáhlo čisté dělitelnosti 16.

LITTLE-ENDIAN

Následující uvedené položky jsou ve formátu Little-Endian (procesory: ARM, x86):

  • uword (unsigned 16-bit)
  • dword (unsigned 32-bit)
  • slong (signed 32-bit)
  • qword (unsigned 64-bit)

Položky typu: byte, sbyte, bytes - jsou jednotlivé samostatné bajty, nesdružené do společného čísla.


Zde jsou uvedeny detailní položky:

 [MASTER PACKET CONTENTS]

  OFFSET   | LEN  |  TYPE  | DATA
  ---------+------+--------+-----------------------------

                             [HEADER]

   0       |   3  |  bytes | header "SDS"
   3       |   1  |   byte | TV = (SDS-product-line) including (S-UDP protocol master-version)
   4       |   1  |   byte | PL = number of 16B chunks - this is the payload_length of [ENCRYPTED PAYLOAD] (example: PL==10 => 160 bytes)
   5       |   1  |   byte | encryption-flag  (NOW ACCEPTS ONLY: 0x10 == XTEA-64-CTR)
   6       |   1  |   byte | reserved
   7       |   1  |   byte | CK1: basic additive checksum for [ENCRYPTED PAYLOAD] (start from (including) byte offset [28] and forward)
   8       |   4  |  dword | user_identifier (correlation identifier) - use this to correlate query to response
  12       |  16  |  bytes | CounterBlock
 ----------+------+--------+----------------------------

                             [ENCRYPTED PAYLOAD] -> everything from this point is included:

  28       |   1  |   byte | random number (shall be always different than what was used ever before)
  29       |   1  |   byte | CK2: basic additive checksum for [HEADER] (all bytes [0] to [27] included, BUT: skipping byte [7])
  30       |   2  |  uword | XR_MTU value (maximal size of the custom-payload data including R) ( XL + R <= XR_MTU )
  32       |   4  |  dword | CRC-32 (part-header and plain-text payload) -> byte [36] (included) up to [52+XL-1] (the R area is not included here)
  36       |   4  |  dword | uptime (msecs from boot)
  40       |   4  |  dword | time (epoch) (or, if no NTP is available to SDS, this will be a value of "seconds from boot")
  44       |   4  |  dword | SDS device type (0xXXXXXXXX) - THIS MUST MATCH
  48       |   1  |   byte | master_command
  49       |   1  |   byte | sub_command
  50       |   2  |  uword | XL value (exact length of the actually useful payload-data): XL = (PL*16) - R - 24

  52       |  XL  |  bytes | custom payload-data [C-PAYLOAD]

  52+XL    |   R  |  bytes | specific set of (random data filling) to round-up (the PL*16 value) to a clean 16B multiply (16, 32, 64, etc.)

 ----------+------+--------+----------------------------

Hodnota "SDS device type" je určena podle typu SDS, se kterým komunikujete. Seznam hodnot viz Firmware, například 0xB1900001 pro BIG-64 nebo 0xB1900002 pro BIG-128 atd.Pokud tato hodnota neodpovídá typu firmware v daném SDS, bude paket zcela ignorován a neproveden. Jediná vyjímka je master_command == NOP, což je záměrná vyjímka, která umožní zjištění typu SDS (a přítomnosti SDS) při zahájení komunikace.

Hodnota "random number" je zde proto, aby šifrované data byly pokaždé jiné, i když se přenáší stejný obsah (tzn. jedná se o zábranu stenografického odhadu obsahu payloadu).

Hodnota "time" umožňuje zařízení, které komunikuje s SDS, zabránit "replay" útoku (když se zaznamená paket a později se zopakuje - v takovém případě se na to přijde protože "time" bude významně starší). SDS kontrolu provádí vůči svému vnitřnímu času, vzdálené zařízení co se SDS komunikuje by tuto kontrolu mělo dělat také.

Protože hodnota "time" se zvyšuje pouze co 1 vteřinu, je k dispozici i hodnota "uptime" která se po resetu/bootu (kde se nastaví na nulu) zvyšuje každou 1 milisekundu o jedničku. Kombinace umožňuje vhodně sestavit algoritmus detekce "replay" útoků.

"CounterBlock" se využívá pro nastavení začátku šifrování a dešifrování. Všechny detaily jsou zcela shodné jako pro FULL-C funkci SDS_Crypt(). Z hlediska bezpečnosti je důležité, aby obě strany neustále používaly zvyšující se CounterBlock obsah (začít "od jedničky" pouze a jenom po resetu/bootu), tzn. pro každou zprávu použít poslední hodnotu counteru a na té dále stavět pro novou zprávu atd. .

Hodnota "crc32" se počítá pro dešifrované data, algoritmus je identický jako pro FULL-C funkci SDS_Crypt().

Pro zvolené XTEA-64-CTR má "CounterBlock" následující sestavu svého obsahu:

  CounterBlock:

  OFFSET    | LEN  |  TYPE  |  DATA
  ----------+------+--------+-----------------------------------------------------------------------------------------
   0        |   8  |  qword |  XTEA-64-CTR: 64-bit counter (counter is increased by 1, for each 16B of processed data)
   8        |   8  |  bytes |  (reserved) not-used area = reserved (fill with 0x00) 

Pro jiné mechanismy (do budoucna) je v CounterBlock oblasti přidána ještě 8B rezerva (např. pro AES-128 se pak využije všech 16 bajtů).


Hodnota "TV" (v [HEADER] na offsetu [3]) je určení typu a verze protokolu. Skládá se ze dvou čtyřbitových údajů, viz následující tabulka.

TV: ttttVVVV
    76543210

BIT OFFSET | LEN (bits) | content
-----------+------------+--------------------------------------------------
 7 (MSB)   |          4 |  "t": produc-line value: 1 == first, 2 == second
 3         |          4 |  "V": version: 0 = first S-UDP protocol version


V konečném důsledku, skutečnou funkční důležitost ma [C-PAYLOAD], což je blok dat, který obsahuje hodnoty a příkazy, které pomocí S-UDP chceme přenést.


Postup při příjmu S-UDP paketu

Každá strana, která přijme S-UDP paket, provede následující kroky:

1) Ověřit platnost hodnot v [HEADER]
   a. text "SDS" (platný obsah)
   b. hodnota "TV" ("master-version" a "product-line") (platný obsah)
   c. hodnota "PL" v platných mezích
   d. hodnota "encryption_flag" (platný obsah)
2) Ověřit základní additive-checksum pro [ENCRYPTED PAYLOAD]
   a. přečíst bajty [28] až [28+PL-1] a sečíst je (overflow osm bitů), výsledek musí odpovídat "CK1" hodnotě
3) Nastavit dešifrování
   a. zvolit algoritmus podle "encryption-flag" hodnoty
   b. nastavit klíč (stejný jako na protistraně, samozřejmě není přenášen přes síť)
   c. nastavit "CounterBlock" (přečíst z [HEADER])
4) Dešifrovat celou [ENCRYPTED PAYLOAD] na plain-text
   a. hodnota "PL" musí být dělitelná 16 beze zbytku (tato podmínka závisí na použitém šifrovaní)
5) Ověřit základní additive-checksum pro [HEADER] - teď totiž už máme hodnotu "CK2"
   a. přečíst bajty [0] až [27] (ovšem přeskočit byte [7] - pozor!) a sečíst je (overflow osm bitů), výsledek musí odpovídat "CK2" hodnotě
6) Ověřit další hodnoty
   a. "SDS-DEVICE-TYPE" musí odpovídat (záruka ovládání toho správného typu SDS) - pokud hodnotu nevíte, můžete si "pomoci" NOP příkazem
   b. uschovat hodnotu "XR_MTU" pro vytváření odpovědi ("XR_MTU" omezuje velikost odpovědi, kterou můžeme zpátky odeslat)
   c. ověřit časové údaje ("time" a "uptime")
   d. ověřit "XL" vůči "PL"
7) Ověřit CRC-32 dešifrovaného payloadu
   a. spočítat CRC-32 správným algoritmem, vučí bajtům (plain-text) z [36] až [52+XL-1] včetně

8) Hotovo: teď se provede aktuální příkaz (Master Command, dle tabulky podle produktové řady viz "TV")
           a odešle odpověď (ponechat user_identifier pro korelaci) (pozor na "XR_MTU" omezení)


Postup při odesílání S-UDP paketu

Odesílatel zprávy provádí tyto kroky:

1) Je sestaven přesný obsah [C-PAYLOAD] a určena odpovídající hodnota XL
   a. obsah samozřejmě odpovídá tomu co chcete odeslat
   b. určí se i "master-command" a "sub-command" (pozor na produktovou řadu SDS - viz "TV")
2) Vyplní se [HEADER]
   a. hlavička "SDS", "encryption-flag"
   b. zapsat správnou hodnotu "TV" podle protokolu a konkrétního SDS ("master-version", "product-line")
   c. určí se nová unikátní hodnota "user_identifier", a zapíše se do [HEADER]
   d. zapíše se "CounterBlock" (hodnota pokračuje po předchozím paketu)
3) Nachystá se zaokrouhlovací oblast "R" 
   a. Pokud XL není beze zbytku dělitelná 16, musí se doplnit oblastí "R"
4) Spočítá se hodnota "PL"
   a. PL = (XL + R)/16
   b. zapsat do [HEADER]
5) Začne se vyplňovat [ENCRYPTED PAYLOAD]
   a. zapsat náhodný byte do "random number"
   b. spočítá se hodnota "CK2" (sečíst bajty [0] až [27] - ovšem přeskočit byte [7] - pozor!) 
   c. zapsat hodnotu "XR_MTU" podle možností zařízení (tzn. jak velkou odpověď lze bezpečně přijmout, podle omezení sítě)
   d. zapíší se hodnoty "uptime" a "time", zapsat hodnotu "SDS-DEVICE-TYPE"
   e. zapsat "master-command" a "sub-command"
6) Spočítá se CRC-32 (před šifrováním)
   a. spočítat crc32 pro bajty (plain-text) z offsetu [36] až [52+XL-1] včetně
7) Nastavit šifrování
   a. zvolit algoritmus (musí odpovídat tomu, co se zapsalo do "encryption-flag")
   b. nastavit klíč (stejný jako na protistraně, samozřejmě není přenášen přes síť)
   c. nastavit "CounterBlock" (stejný jako byl zapsán [HEADER])
8) Šifrovat celou [ENCRYPTED PAYLOAD] na plain-text
   a. hodnota "PL" musí být dělitelná 16 beze zbytku (tato podmínka závisí na použitém šifrovaní)
   b. aktualizovaná hodnota "CounterBlock" (zvýšená o průběh šifrování) se uschová pro další použití - viz bod " 2) c. "
9) Spočítat základní additive-checksum pro [ENCRYPTED PAYLOAD]
   a. přečíst bajty [28] až [28+PL-1] a sečíst je (overflow osm bitů), výsledek se zapíše do "CK1" hodnoty

10) Hotovo: paket se následně odešle přes síť do protistrany, která odpoví novým paketem - ten je vztažen k tomuto dotazu pomocí "user_identifier" hodnoty.


Vzorové obsahy paketů

Na stránce M2M: S-UDP protocol: examples naleznete ukázkové vzorové pakety a jejich vnitřní obsah, i se zobrazeních jednotlivých položek v paketu (před a po šifrování). Toto je vhodné pro vývojáře komunikační protistrany, kterým nestačí popis postupu na této stránce, ale chtějí také vidět jednotlivé kroky s aktuálními hodnotami.


Seznam hlavních příkazů

Obě produktové řady SDS, které jsou na trhu, mají svou sadu "master_command" příkazů. Proto je potřeba nejprve zjistit, do které produktové řady vaše SDS spadá, a podle toho dále pokračovat. Lze to přímo odvodit od typu SDS ("SDS-DEVICE-TYPE" hodnota), nebo se zeptat příkazem NOP.

Zařazení SDS do produktových řad je v tomto seznamu.

  • První produktová řada: "TV = 0001...." -> (1PŘ)
  • Druhá produktová řada: "TV = 0010...." -> (2PŘ)


(2PŘ) Master Command (druhá produktová řada: "TV = 0010...." )

Jednotlivé základní příkazy (master command):

 MASTER COMMAND  |  command
 ----------------+-------------------------------------
    0            |   NOP (replies with NOP)
    1            |   general device status
    2            |   1-Wire access
    4            |   read FC-Get list
    8            |   write FC-Set list
   16            |   FULL-C shared variable(s) access
   32            |   serial port access
   64            |   DataFlash access
  128            |   reserved

Jak lze vidět, jednotlivé master command příkazy jsou dále rozlišeny pomocí hodnoty sub command.

Každý příkaz má doplňující datovou sadu, tzn. [C-PAYLOAD]. V rámci těchto dat jsou uvedeny všechny hodnoty, které přesně určují co se má stát (popř. jsou zde všechny odpovědi na dotaz).


(2-PŘ) Master Command: [0] NOP

SDS odpoví na tento příkaz odesláním [0] NOP.

Tohoto příkazu lze využít k ověření komunikace a k vzájemné základní synchronizace.

Specifická vlastnost příkazu NOP, oproti všem ostatním příkazům, je to, že SDS odpoví i v případě, že v dotazu není správně uvedený SDS Device Type. Toto je záměr, aby bylo možné při začátku komunikace s SDS modulem, tento modul identifikovat. Samozřejmě všechny ostatní bezpečnostní prvky jsou stále aplikovány, jen tento detail je zde upraven.

Tento příkaz je také velmi užitečný pro získání hodnoty "TV" z [HEADER], tím pádem pro určení číslo produktové řady SDS - a tím pádem k určení které "master_command" příkazy jsou k dispozici !

REPLY (master_command == 0, sent from SDS as reply)
sub_command = 0

C-PAYLOAD offset | LEN   | TYPE  | content
-----------------+-------+-------+------------------------------------------------------
   0             |     6 | bytes |  MAC ADDRESS (bytes, not text)
   6             |     4 | bytes |  SDS Device Type
  10             |     4 | dword |  FW version 
  14             |    32 | bytes |  sysLocation (missing the 0x00 terminator)
  46             |     8 | bytes |  reserved (0x00)
  54             |    32 | bytes |  OEM string (missing the 0x00 terminator)
  86             |     8 | bytes |  reserved (0x00)
  94             |     1 |  byte |  bylo aktivováno RSTD
  95             |     1 |  byte |  bylo aktivováno PVD
  96             |     1 |  byte |  SDS je: BIG (hodnota 1) nebo STSW (hodnota 0)
  97             |     8 | bytes |  reserved (0x00)
 105             |     2 | uword |  web interface TCP port number (typicky 80)
 107             |     1 |  byte |  SNMP-read enabled
 108             |     1 |  byte |  SNMP-write enabled
 109             |     1 |  byte |  FULLC shared vars access lock (0 = unlocked) tzn. sys[150]
 110             |     1 |  byte |  FULLC program run status
 111             |     1 |  byte |  FULLC program started-by info
 112             |     1 |  byte |  FULLC program watchdog active
 113             |     6 | bytes |  reserved
 119             |     4 |   f32 |  backup battery voltage (milliVolts)

Pozn. rozšířená funkcionalita příkazu NOP (tedy vracení payloadu) bylo přidáno až ve Firmware od verze 3.10.2019.


(2-PŘ) Master Command: [1] General Device Status

SDS odpoví zasláním vybraných údajů, jejichž seznam je přesně daný. Tato funkce je k dispozici pro umožnění rychlého přístupu k základnímu stavu zařízení SDS, bez složité přípravy.

Základní odpověď s nejzajímavějšími živými údaji. Určeno např. pro průběžnou aktualizaci stavu zobrazeného uživateli.

REPLY (master_command == 1, sent from SDS as reply)
sub_command = 0

C-PAYLOAD offset | LEN   | TYPE  | content
-----------------+-------+-------+------------------------------------------------------
   0             |     6 | bytes |  MAC ADDRESS (bytes, not text)
   6             |     1 |  byte |  Ethernet Link Status / Speed (0, 10, 100)
   7             |     1 |  byte |  Amount of users logged into SDS Web Admin
   8             |    32 | bytes |  sysLocation (missing the 0x00 terminator)
  40             |     1 |  byte |  IP Watchdog Config status
  41             |     1 |  byte |  IP Watchdog Output (relay) status
  42             |     2 | uword |  IP Watchdog RTT value (note.: 0xFFFF = not available)
  44             |     1 |  byte |  DHCP status
  45             |     1 |  byte |  reserved
  46             |     1 |  byte |  NTP status
  47             |     1 | sbyte |  NTP offset (+/- hours) (signed char)
  48             |     2 | uword |  SoC chip temperature (degC)
  50             |     1 |  byte |  GPIO-TOPB PIN(s) direction (0 == input)
  51             |     1 |  byte |  GPIO-TOPB PIN(s) pin value
  52             |  32*1 |  byte |  OPTO [1]..[32] status (0xFF == signal) (0x00 == nosignal)
  84             |  32*1 |  byte |  RELAY [1]..[32] status (active/nonactive)
 116             |  32*2 | uword |  ADC [0]..[31] RAW value
 180             |     1 |  byte |  General 1-W BUS status
 181             |     1 |  byte |  1-W BUS A - active device count
 182             |     1 |  byte |  1-W BUS B - active device count
 183             |     3 | bytes |  reserved (0x00)
 186             |     1 |  byte |  S0 Tariff Value (active/nonactive)
 187             |     1 |  byte |  number of the following S0 INPUT DB data blocks:
 188             | 31*28 |  data |  S0 INPUT [1]..[ (max) 31] DB (data block)


S0-INPUT DB offset | LEN | TYPE  | content
-------------------+-----+-------+-------------------------------------------------------
   0               |   1 |  byte |  configuration status (combined flags: bit0 = enabled as S0; bit1 = is tariff used)
   1               |   3 | bytes |  reserved (filled with 0x00)
   4               |   4 | dword |  T0 impulse counter
   8               |   4 | dword |  T1 impulse counter
   12              |   4 | dword |  T0 offset
   16              |   4 | dword |  T1 offset
   20              |   4 | dword |  measured space between impulses (msec)
   24              |   4 | dword |  time since last registered impulse (msec)

Sestava [C-PAYLOAD] je tedy zřejmá.

Poslední blok (offset [188] až [1083] včetně) je určen pro přenos 32 S0 vstupů - často je jich ale v zařízení SDS fyzicky přítomno mnohem méně, např. jen devět - a potom zařízení SDS ve své odpovědi pošle jen devět záznamů (namísto 32) (toto se týká pouze a jenom S0 položek, né jiných v rámci paketu). To je provedeno z praktického důvodu: aby byl UDP paket dostatečně malý (a tedy rychlý na zpracování).


(2-PŘ) Master Command: [2] 1-Wire Access

Tato funkce se používá pro čtení stavu hodnot získaných z obou 1-W sběrnic, kterými SDS disponuje (některé SDS mají jen jednu sběrnici). Maximální počet prvků (chipů) na sběrnici je 64, celkem je tedy k dispozici 2x64 = 128 prvků.

QUERY/COMMAND TO SDS (master_command == 2)

sub_command | meaning
------------+-----------------------------------------------------------
          0 |  reserved
          1 |  obtain status, and list of found items on BUS A
          2 |  obtain status, and list of found items on BUS B
          4 |  list all read-values on BUS A
          8 |  list all read-values on BUS B

První možností tedy je sub_command == 1 , tzn. výpis nalezených zařízení na sběrnici A respektive B:

REPLY (master_command == 1, sent from SDS as reply)
sub_command = 1 or 2

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  global 1-W controller status (SDS status)
   1             |   1 |  byte |  number of active items on BUS A
   2             |   1 |  byte |  number of active items on BUS B
   3             |   1 |  byte |  reserved (0x00)
   4             |  12 |  data |  1-W item status #0
   . . .         | ... |   ... |  . . .
   4+12*63       |  12 |  data |  1-W item status #63

"1-W item status" ofs | LEN | TYPE  | content
----------------------+-----+-------+-------------------------------------------------------
   0                  |   1 |  byte |  ctrl: main-status
   1                  |   1 |  byte |  ctrl: sub-status 
   2                  |   2 | bytes |  reserved (filled with 0x00)
   4                  |   8 | bytes |  ROM-CODE [0]..[7]

Následuje: výpis získaných hodnot (např. změřené teploty z teplotních čidel) pro jednotlivé sběrnice :

REPLY (master_command == 1, sent from SDS as reply)
sub_command = 4 or 8

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  global 1-W controller status (SDS status)
   1             |   1 |  byte |  number of active items on BUS A
   2             |   1 |  byte |  number of active items on BUS B
   3             |   1 |  byte |  reserved (0x00)
   4             |  12 |  data |  1-W item value #0
   . . .         | ... |   ... |  . . .
   4+12*63       |  12 |  data |  1-W item value #63

"1-W item value" ofs  | LEN | TYPE  | content
----------------------+-----+-------+-------------------------------------------------------
   0                  |   1 |  byte |  ctrl: main-status
   1                  |   1 |  byte |  ctrl: sub-status
   2                  |   1 |  byte |  value of ROM-CODE offset [0] (1-W DEVICE TYPE: ID)
   3                  |   1 |  byte |  value of ROM-CODE offset [7] (1-W DEVICE TYPE: CRC)
   4                  |   4 | slong |  1-W read: primary value
   8                  |   4 | slong |  1-W read: secondary value

Každý chip na sběrnici 1-Wire má vždy primární a sekundární hodnotu, kterou SDS pro daný chip udržuje (ne vždy jsou však, v závislosti na konkrétním chipu, obě hodnoty použity). Aktuální význam je potřeba určit podle chipu (příklad: DS18B20 má "primary value" zpracovanou teplotu v degC, a "secondary value" přímou surovou 16-bit hodnotu přečtenou z čidla).


(2-PŘ) Master Command: [4] Read FC-Get List

Dotaz (query) který obsahuje seznam indexů jejichž hodnoty jsou tazatelem požadovány, se posílá do SDS, které následně odpoví (reply).

Dotaz i odpověď má dynamický obsah, který je specificky strukturován.

QUERY (master_command == 4, sent to SDS)

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------
 0               |   2 | uword | [#0] index value 
 2               |   2 | uword | [#0] TBLEN#0: type-bits and data length (L#0)
 4               | L#0 |  data | [#0] space prepared for answer from SDS

 (4+(L#0))+0     |   2 | uword | [#1] index value
 (4+(L#0))+2     |   2 | uword | [#1] TBLEN#1: type-bits and data length (L#1)
 (4+(L#0))+4     | L#1 |  data | [#1] space prepared for answer from SDS

 . . .           | ... | . . . | ...

 Z+0             |   2 | uword | [#n] index value 
 Z+2             |   2 | uword | [#n] TBLEN#n: type-bits and data length (L#n)
 Z+4             | L#n |  data | [#n] space prepared for answer from SDS

Jak lze vidět, v dotazu (query) jsou za sebou naskládány položky (indexy), na které následně SDS odpoví. Vždy musíte u každého indexu, na který se ptáte, uvést typ odpovědi (viz dále) a prostor, kam bude odpověď zapsána - to znamená, musíte znát přesnou délku, kterou má obsah pro daný index !

Pozor na množství dotazů v rámci jednoho paketu, protože velikost dotazu, a také velikost odpovědi, je omezena XR_MTU. Jakmile SDS při skládání odpovědi narazení na XR_MTU protistrany, už více odpovědí do paketu nepřidá (aby nebylo XR_MTU překročeno).

REPLY (master_command == 4, sent from SDS as reply to query)

SDS writes the values into the "[#n] space prepared for answer from SDS"

Odpověď tedy přesně sleduje (vyplňuje) původní dotaz, přičemž [C-PAYLOAD] teď obdrží skutečný datový obsah pro jednotlivé položky. Pokud poskytnete SDS menší prostor pro odpověď, než je potřeba, bude odpověď vyplněna 0x00.

Hodnota "sub_command" je nastavena SDS na počet položek (#n) v odpovědi. Toto omezuje maximální počet položek v jednom paketu na 255.

Následující popis ukazuje kódování typu proměnné a její délky, ve společném slově:

TBLEN#x: (16-bit unsigned word, little-endian) Type-Bits and Data Length (L#x)

TBLEN#x: TTTTvvvvvvvvvvvv
         FEDCBA9876543210

BIT OFFSET (hex) | LEN (bits) | content
-----------------+------------+-----------------------------------------
 F (MSB)         |          4 |  "T": type (see bit-value in next table)
 B               |         12 |  "v": length of data, in bytes

 "T" bit-values | meaning                     | FULL-C set/get
           FEDC |                             | (which function)
----------------+-----------------------------+------------------
           0000 |  unsigned integer (32-bit)  |  _u
           0001 |  signed integer (32-bit)    |  _i
           0010 |  float IEEE-754 (32-bit)    |  _f
           0100 |  string UTF-8 (L#x * 8-bit) |  _a
           1000 |  reserved (do not use)      |  

Horní 4 bity z TBLEN#x tedy určují typ položky. Pro získání délky L#x položky 'x', je potřeba hodnotu TBLEN#x odmaskovat - použít jen dolních 12 bitů.

Je vaším úkolem správně zvolit typ (T) pro každou položku, pokud zvolíte špatně, nebude údaj pro daný index zpracován.


Index Value - každá položka má svůj číselný index, viz seznam všech FULL-C indexů.


(2-PŘ) Master Command: [8] Write FC-Get List

Pokud SDS obdrží zprávu s "master_command == 8", tak nastaví příslušné FULL-C indexy na nové hodnoty (podle obsahu této přijaté zprávy).

SDS na tuto zprávu odpovídá pouze ve smyslu "úspěch" nebo "neúspěch" - takže pro skutečné ověření hodnot (zda-li se zapsaly správně) musíte proto sami zaslat další zprávu "master_command == 4".

COMMAND TO SDS (master_command == 8, sent to SDS)

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------
 0               |   2 | uword | [#0] index value 
 2               |   2 | uword | [#0] TBLEN#0: type-bits and data length (L#0)
 4               | L#0 |  data | [#0] new data value to write to SDS

 (4+(L#0))+0     |   2 | uword | [#1] index value
 (4+(L#0))+2     |   2 | uword | [#1] TBLEN#1: type-bits and data length (L#1)
 (4+(L#0))+4     | L#1 |  data | [#1] new data value to write to SDS

 . . .           | ... | . . . | ...

 Z+0             |   2 | uword | [#n] index value 
 Z+2             |   2 | uword | [#n] TBLEN#n: type-bits and data length (L#n)
 Z+4             | L#n |  data | [#n] new data value to write to SDS

Lze vidět, že formát je naprosto shodný jako formát odpovědi kterou SDS posílá pro "master_command == 4" zprávu. Nicméně, v tomto případě, je tento obsah [C-PAYLOAD] zapsán do SDS, které jej zpracuje a provede - pouze ale pokud je délka L#x přesně odpovídající danému indexu.

Odpověď, kterou na tento příkaz SDS následně posílá, je velmi jednoduchá: [C-PAYLOAD] není vůbec použito (XL=0), a "sub_command" obsahuje následující možnost:

REPLY FROM SDS (master_command == 8)

sub_command | meaning
------------+-----------------------------------------------------------
          0 |  complete failure (no item modified)
          1 |  partial failure  (some items modified, some not modified)
          2 |  success          (all items modified OK)

Další, detailnější, rozlišení selhání (failure) se neprovádí (tzn. SDS neposílá více detailnější informaci ve své odpovědi, než uvedené tři možnosti).


(2-PŘ) Master Command: [16] FULL-C Shared Variable(s) Access

Tento příkaz se využívá k přístupu ke sdíleným proměnným programu FULL-C.

Proměnné se označují vzorem, kde je na začátku velké písmeno určující typ, a pak dvě decimální číslice určující pořadí - tedy sto možných hodnot.

Mohou existovat tyto sdílené proměnné :

  • S00 až S99 (hodnoty: signed 32-bit)
  • U00 až U99 (hodnoty: unsigned 32-bit)
  • F00 až F99 (hodnoty: float 32-bit)
  • T00 až T99 (hodnoty: array/text)

Rozlišování jednotlivých funkcí je závislé na hodnotě "sub_command":

QUERY-or-COMMAND TO SDS (master_command == 16, sent to SDS)

sub_command | meaning
------------+---------------------------------------------
          0 | provide list of all active shared variables
          1 | read from shared variable (single variable)
          2 | reserved
          4 | write to shared variable (single variable)
          8 | reserved

Pro "sub_command == 0" poskytne SDS odpověď, kde je uvedeno zda-li je specifická sdílená proměnná definována v právě aktivním FULL-C programu.

RESPONSE:  LIST OF SHARED VARIABLES: sub_command = 0

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+--------------------------
  0              |  13 | bytes | Uxx existence: bit-field
 13              |  13 | bytes | Sxx existence: bit-field
 26              |  13 | bytes | Fxx existence: bit-field
 39              |  13 | bytes | Txx existence: bit-field

Jak lze vidět, v odpovědi jsou čtyři samostatné bitové pole, každé o délce 100 bitů (plus nevyužitý zbytek 4 bitů na konci). Každý bit přestavuje existenci jedné ze sdílených proměnných, pokud je nastaven na 1 tak proměnná existuje.

Xxx existence: bit-field

BYTE -> [0] . . . [13]
BITS ->  0 . . .   100 (plus 4 at the end, which are not used)

BYTE [0] = bit 0, 1, 2, ..., 7
BYTE [1] = bit 8, 9, 10, ..., 15
...
BYTE [13] = bit 96, 97, 98 ..., 103

example: existence of "U11" => bit 11 => look at BYTE [1]

Takže pro kteroukoliv sdílenou proměnnou si lze nalézt příslušnou pozici, která ukazuje, zda-li právě daná proměnná existuje.


Další, "sub_command == 1" umožňuje z konkrétní (jedné) sdílené proměnné číst.

QUERY TO SDS: READ ONE SHARED VARIABLE: sub_command = 1

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+--------------------------
 0               |   3 | bytes | [#0] name (example: "U25")
 1               |   1 |  byte | reserved (0x00)

A odpověď je:

REPLY FROM SDS: READ ONE SHARED VARIABLE: sub_command = 1

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+--------------------------
 0               |   3 | bytes | [#0] name (example: "F95")
 1               |   1 |  byte | reserved (0x00)
 4               |   2 | uword | [#0] L#0: data length (L#0)
 6               |   2 | uword | reserved (0x0000)
 8               | L#0 |  data | [#0] data value from the shared variable


Dále, pro "sub_command == 4" dojde ke změně hodnoty.

COMMAND TO SDS: WRITE ONE SHARED VARIABLE: sub_command = 4

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+--------------------------
 0               |   3 | bytes | [#0] name (example: "T12")
 1               |   1 |  byte | reserved (0x00)
 4               |   2 | uword | [#0] L#0: data length (L#0)
 6               |   2 | uword | reserved (0x0000)
 8               | L#0 |  data | [#0] new data value to write to shared variable

A odpověď je zde shodná jako odpověd pro "sub_command == 1".


(2-PŘ) Master Command: [32] S0 Input Configuration Query

Určeno pro čtení kalibračních konstant pro S0 vstupy. Současně jsou předány i aktuální (živé) údaje pro daný S0 vstup.

Pozn. master_command == 32 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 32, sent from SDS as reply)
sub_command == index to S0 array [1..MAX] (typical MAX value is 9)

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  S0 input number for this reply (for a valid answer: 1..MAX , otherwise: 0x00).
   1             |   1 |  byte |  total number of S0 inputs for this SDS
   2             |   1 |  byte |  configuration status (combined flags: bit0 = enabled as S0; bit1 = is tariff used)
   3             |   1 |  byte |  reserved (0x00)
   4             |  32 | bytes |  text (name: unit)
   36            |  32 | bytes |  text (name: money)
   68            |  32 | bytes |  text (unit: power)
   100           |  32 | bytes |  text (name: power)
   132           |  32 | bytes |  text (name: device)
   168           |   4 | dword |  MTD value
   172           |   4 | dword |  minimal impulse length (msec)
   176           |   4 | dword |  impulse constant value (imp. per unit)
   180           |   4 | bytes |  price for T0
   184           |   4 | bytes |  price for T1
   188           |   8 | bytes |  reserved (0x00)
   196           |   4 | dword |  live value: T0 impulse counter
   200           |   4 | dword |  live value: T1 impulse counter
   204           |   4 | dword |  T0 offset
   208           |   4 | dword |  T1 offset
   212           |   4 | dword |  live value: measured space between impulses (msec)
   216           |   4 | dword |  live value: time since last registered impulse (msec)
   220           |   4 | bytes |  reserved (0x00)
   224           |   n | bytes |  live value: combined text

Kombinovaný text (combined text) obsahuje vypočtené informace, oddělené znakem '|'. Tyto údaje lze přímo zobrazit uživateli. Výpočet provádí SDS, a stejné hodnoty ukazuje na svém webu. Jedná se zde o doplněk původní funkce GDS (master_command==0).

Délka textu "n" je dynamická, text je zakončen 0x00 (nebo pokud vyjde přesně na maximální délku co se vleze do payloadu, zakončení nemá a je uříznut na posledním znaku, pozor na to).


(sub_command = 0xFF): speciální odpověď pro Tarifní vstup :

REPLY (master_command == 32, sent from SDS as reply)
sub_command == 0xFF (tariff)

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  constant 0xFF
   1             |   3 | bytes |  reserved (0x00)
   4             |   1 |  byte |  tariff input
   5             |  32 | bytes |  text (name: tariff)
   37            |  32 | bytes |  text (name: tariff T0 input)
   69            |  32 | bytes |  text (name: tariff T1 input)


(2-PŘ) Master Command: [33] S0 Input History Values

Určeno pro čtení historických hodnot počítadel pro vybraný S0 vstup. Každá nová položka se do záznamu historie uloží co 15 minut.

Pozn. master_command == 33 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 33, sent from SDS as reply)
sub_command == index to S0 array [1..MAX] (typical MAX value is 9)

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  S0 input number for this reply (for a valid answer: 1..MAX , otherwise: 0x00).
   1             |   1 |  byte |  total number of S0 inputs for this SDS
   2             |   1 |  byte |  configuration status (combined flags: bit0 = enabled as S0; bit1 = is tariff used)
   3             |   3 | bytes |  reserved (0x00)
   6             |   2 |  word |  history depth (number of items) - value "n" (example: five items -> n == 5)
   8             |   4 | dword |  uptime value for the last element (#n) in the list
   12            |   4 | dword |  ntptime value for the last element (#n) in the list
   16            |   4 | dword |  history item #1: value of T0 counter (this is the most oldest item)
   20            |   4 | dword |  history item #1: value of T1 counter (this is the most oldest item)
   ...
   16+(n-1)*8    |   4 | dword |  history item #n: value of T0 counter (this is the most newest item)
   16+(n-1)*8+4  |   4 | dword |  history item #n: value of T1 counter (this is the most newest item)

Historické údaje počítadel ukazují stav počítadel od současnosti dozadu. Položka #1 je nejstarší, pak #2 je mladší atd. až po položku #n která je nejaktuálnější (nejbližší současné chvíli).


(2-PŘ) Master Command: [40] AD Input Configuration Query

Určeno pro čtení kalibračních konstant pro AD vstupy.

Pozn. master_command == 40 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 40, sent from SDS as reply)
sub_command == index to AD array [1..MAX]

C-PAYLOAD offset | LEN  | TYPE  | content
-----------------+------+-------+------------------------------------------------------
   0             |   1  |  byte |  actual AD input index for this reply
   1             |   1  |  byte |  total number of AD inputs
   2             |   2  | bytes |  reserved (0x00)
   4             |   4  |   f32 |  F6 calibration constant
   8             |   4  |   f32 |  F5 calibration constant
  12             |   4  |   f32 |  F4 calibration constant
  16             |   4  |   f32 |  F3 calibration constant
  20             |   4  |   f32 |  F2 calibration constant
  24             |   4  |   f32 |  F1 calibration constant
  28             |   4  |   f32 |  F0 calibration constant
  32             |   1  |  byte |  is calibration factory locked
  33             |  32  | bytes |  unit
  65             |   4  | bytes |  reserved (0x00)
  69             |  32  | bytes |  name
 101             |   4  | bytes |  reserved (0x00)
 105             |   4  | dword |  raw value
 109             |   4  |   f32 |  real value (converted from raw)
 113             |   n  | bytes |  live value text

Text "live value" obsahuje hodnotu vypočtenou interně v SDS. Text lze prezentovat uživateli (je to stejné jako co SDS ukáže na svém webu). Jedná se o doplňkovou funkci vůči vlastnímu výpočtu ze surových hodnot z GDS (master_command==0).


(2-PŘ) Master Command: [42] PWM Output Configuration Query

Určeno pro čtení nastavení pro PWM výstup (konfigurace a živý stav).

Pozn. master_command == 42 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 42, sent from SDS as reply)
sub_command == 0

C-PAYLOAD offset | LEN  | TYPE  | content
-----------------+------+-------+------------------------------------------------------
   0             |   1  |  byte |  reserved (0x00)
   1             |   1  |  byte |  "N" = total number of PWM outputs
   2             |   2  | bytes |  reserved (0x00)

   4+(i*12)+  0  |   4  | dword |  frequency (Hz) for PWMx
   4+(i*12)+  4  |   4  | dword |  "pulse" value for PWMx
   4+(i*12)+  8  |   1  |  byte |  "ValueB" value for PWMx
   4+(i*12)+  9  |   2  | uword |  "ValueS" value for PWMx
   4+(i*12)+ 11  |   1  |  byte |  output enabled for PWMx

Pozn. PWM1 má hodnotu "i" = 0, PWM2 má hodnotu "i" = 1 atd.

V případě, že je některý z PWMx výstupů nevyužit ("přeskočen"), je přesto v odpovědi uveden, aby bylo zachováno číslovaní pořadí všech PWMx výstupů.


(2-PŘ) Master Command: [44] RELAYs Configuration Query

Určeno pro čtení konfigurace RELAY výstupů (nastavení a živý stav).

Pozn. master_command == 44 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 44, sent from SDS as reply)
sub_command == index to RELAY array [1..MAX]

C-PAYLOAD offset | LEN  | TYPE  | content
-----------------+------+-------+------------------------------------------------------
   0             |   1  |  byte |  actual RELAY output index for this reply
   1             |   1  |  byte |  total number of RELAY outputs
   2             |   2  | bytes |  reserved (0x00)
   4             |  32  | bytes |  name
  36             |   4  | bytes |  reserved (0x00)
  40             |   1  |  byte |  "relay-controlled-by" value
  41             |   1  |  byte |  "relay-output" value


(2-PŘ) Master Command: [48] SD Card Status Query

Určeno pro čtení stavu SD karty.

Pozn. master_command == 48 byl přidán až ve Firmware od verze 3.10.2019.

REPLY (master_command == 48, sent from SDS as reply)
sub_command == 0

C-PAYLOAD offset | LEN | TYPE  | content
-----------------+-----+-------+------------------------------------------------------
   0             |   1 |  byte |  card mounted 
   1             |   3 | bytes |  reserved
   4             |   4 | dword |  card type
   8             |   4 | dword |  card ProdSN
  12             |   4 | dword |  card init attempts counter
  16             |   4 | dword |  card init failures counter
  20             |   4 | dword |  card total sector count in FAT in KiB
  24             |   4 | dword |  total sector reads counter
  28             |   4 | dword |  total sector writes counter
  32             |   4 | dword |  total sector r/w failures counter


(2-PŘ) Master Command: [50] Serial Port Access

Tento příkaz není pro "version == 0x00" podporován. Potřebujete novější firmware.


(2-PŘ) Master Command: [64] DataFlash (NVM) Access

Tento příkaz není pro "version == 0x00" podporován. Potřebujete novější firmware.


(2-PŘ) Master Command: [128] Reserved

Tento příkaz není v současné verzi použit.


(1-PŘ) Master Command (první produktová řada: "TV = 0001...." )

Jednotlivé základní příkazy (master command) - zatím nejsou pro první produktovou řadu definovány.

Detaily zde budou doplněny.