https://www.s5tech.net/viewtopic.php?f=47&t=354,
kjer je Vilko predstavil svoj način komuniciranja s sužnji.
Tam sem mu predlagal poenostavljen protokol v naslednji sestavi:
- Koda: Izberi vse
Byte 01: [Start] – start byte
Byte 02: [ID] – številka sužnja
Byte 03: [Komanda] – tukaj lahko v en bayte zakodiraš 255 komand
Byte 04: [podatki] – telegram lahko vsebuje podatke če je to potrebno. Preko tega lahko enostavno razširiš tudi število komand.
.
.
Byte n-1: [CRC hi]
Byte n: [CRC Lo]
Med drugim je dobra lastnost takčnega protokola, da se ga da enostavno obdelati že v sami prekinitveni rutini.
V nadaljevanju je primer kode za to obdelavo. Gre torej za fragment kode, ki je nameščena v prekinitvi serijskega porta, ki se izvrši ob vsakem sprejetem baytu. Prehod med posameznimi fazami dekodiranja poteka s pomočjo t.i. FSA (Finite State Automata). Variabla IntSer_Rx_State je torej kazalec med posameznimi stanji dekodiranja. C kodo sem malce spremenil, da je bolj čitljiva tudi tistim, ki C ne poznajo.
- Koda: Izberi vse
/* najprej prenesemo sprejeti podatek v variablo ComChr */
ComChr = SBUF;
/* Resetiraj FSA, ce je cas sprejema predolg */
if (RTX_FSA_Rx_TimeOut == 0) IntSer_Rx_State = 0;
switch (IntSer_Rx_State)
{
case 0: // ---------- START Byte
if (TG_Sprejet_F == 1) break; // prejsnji TG se ni obdelan
if (ComChr == _TG_START_BYTE) // obdelavo zacni s START Bytom
{
RTX_FSA_Rx_TimeOut = _RX_TIMEOUT; // nastavi TimeOut cas
RTX_Buffer_Crc = 0; // Inicializacija CRC
IntSer_Rx_State++; // Naslednji je address byte
}
break;
case 1: // ---------- ADDRESS Byte
if ((ComChr == DEVICE_ADDRESS)||(ComChr == 0xFF))
{
RTX_Buffer_Ptr = 0; // kazalec bufferja na zacetek
RTX_Buffer[RTX_Buffer_Ptr] = ComChr; // vpisi znak v buffer
RTX_Buffer_Ptr++; // kazalec na naslednji znak v bufferju
RTX_Buffer_Crc = CRC16(RTX_Buffer_Crc, ComChr); // Izracun CRC
++IntSer_Rx_State; // Naslednji je command byte
}
else
{
// Telegram ni namenjen tej napravi, zato pojdi na zacetek
IntSer_Rx_State = 0;
}
break;
case 2: // ---------- COMMAND Byte
RTX_Buffer_Crc = CRC16(RTX_Buffer_Crc, ComChr); // Izracun CRC
RTX_Buffer[RTX_Buffer_Ptr] = ComChr; // vpisi znak v buffer
RTX_Buffer_Ptr++; // kazalec na naslednji znak v bufferju
IntSer_Rx_State++; // Naslednji je data_size byte
break;
case 3: // ---------- DATA_SIZE Byte
if (ComChr > (_TG_BUFF_LEN-4)) // je dolzina podatkov OK ?
{
IntSer_Rx_State = 0; // NE, zato pojdi na zacetek
break;
}
RTX_Buffer_Crc = CRC16(RTX_Buffer_Crc, ComChr); // Izracun CRC
RTX_Buffer[RTX_Buffer_Ptr] = ComChr; // vpisi znak v buffer
RTX_Buffer_Ptr++; // kazalec na naslednji znak v bufferju
RTX_Buffer_Len = ComChr; // Shrani dolzino telegrama
IntSer_Rx_State++; // Sledi data byte ...
// ... oziroma CRC preverjanje, ce je LEN=0
if (RTX_Buffer_Len == 0) IntSer_Rx_State++;
break;
case 4: // ---------- DATA Byte
RTX_Buffer_Crc = CRC16(RTX_Buffer_Crc, ComChr); // Izracun CRC
RTX_Buffer[RTX_Buffer_Ptr] = ComChr; // vpisi znak v buffer
RTX_Buffer_Ptr++; // kazalec na naslednji znak v bufferju
RTX_Buffer_Len--; // v telegramu je en podatek manj, zato
// zamanjsamo dolzino in zakljuci, ce LEN=0
if (RTX_Buffer_Len == 0) ++IntSer_Rx_State;
break;
case 5: // ---------- CRC_HI Byte
if (ComChr == (RTX_Buffer_Crc >> 8)) ++IntSer_Rx_State;
break;
case 6: // ---------- CRC_LO Byte
if (ComChr == (RTX_Buffer_Crc & 0x00FF))
{
TG_Sprejet_F = 1; // Indikacija sprejetega telegrama
}
IntSer_Rx_State = 0; // FSA na zacetek
break;
default: // ---------- Nedovoljeno stanje / verjetno motnja ali napaka
ResetCPU();
break;
}
}