Ah ok,
Yes I agree. I have actually come up with a, let's say 'data flow program structure' like you describe.
I could describe my whole program flow here, but posting the code is probably the thing to do.
So here is my TX and RX code so far, not perfect but it seems to work and might be of help to someone someday.
TX code
#include <Streaming.h>
/*
Arduino Nano Every Serial Ports:
(https://forum.arduino.cc/t/arduino-nano-every-access-to-4-serial/614358)
Serial -> USB interface
Serial1 -> D0 (RX) / D1 (TX) Stepper 1 PAN
Serial2 -> D7 (RX) / D2 (TX) Stepper 2 TILT
Serial3 -> D3 (RX) / D6 (TX) RS485 DATA
*/
/*==============================
_____ ______ ______ __ __ ____
/ ___/ / ____//_ __// / / // __ \
\__ \ / __/ / / / / / // /_/ /
___/ // /___ / / / /_/ // ____/
/____//_____/ /_/ \____//_/
*/
void setup()
{
Serial.begin(115200); // Hardware serial for debugging over USB
Serial1.begin(4800); // Hardware serial data port
}
/*==============================
__ ____ ____ ____
/ / / __ \ / __ \ / __ \
/ / / / / // / / // /_/ /
/ /___/ /_/ // /_/ // ____/
/_____/\____/ \____//_/
*/
void loop(){
int ack_timeout = 300; // Max time to wait for ack
unsigned long time_sent = millis(); // Mark the time of sending
unsigned long time_waiting = 0; // The time the loop has been waiting for an ack
bool ack_received = false;
while(Serial1.available()) Serial1.read(); // Empty serial buffer for ack
transmit(); // Send out one message/byte
while(time_waiting < ack_timeout)
{
if(Serial1.available() >= 4)
{
ack_received = true;
byte ack[4];
Serial1.readBytes(ack, 4);
Serial.println(ack[3], HEX);
break;
}
time_waiting = millis() - time_sent;
}
if(!ack_received) Serial << "ack_timeout" << endl;
//delay(5);
}
/*=========================================================
______ ____ ___ _ __ _____ __ ___ ____ ______
/_ __// __ \ / | / | / // ___/ / |/ // _//_ __/
/ / / /_/ // /| | / |/ / \__ \ / /|_/ / / / / /
/ / / _, _// ___ | / /| / ___/ // / / /_/ / / /
/_/ /_/ |_|/_/ |_|/_/ |_/ /____//_/ /_//___/ /_/
Function Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
Start Address CMD1 CMD2 Data1 Data2 Checksum
Left 0xFF Address 0x00 0x04 Pan Speed 0x01 - 0x3F 0x00 SUM
Right 0xFF Address 0x00 0x02 Pan Speed 0x01 - 0x3F 0x00 SUM
Up 0xFF Address 0x00 0x08 0x00 Tilt Speed 0x01 - 0x3F SUM
Down 0xFF Address 0x00 0x10 0x00 Tilt Speed 0x01 - 0x3F SUM
*/
void transmit(){
static int index = 0;
/* Consistent data ===========================
const uint8_t bytes_to_send[][7] =
{
{0xFF, 0x11, 0x1A, 0xFB, 0x5C, 0x6D, 0xEF}, // 1 1 start byte, 5 data bytes, 1 checksum (calculated )
{0xFF, 0x01, 0x00, 0x02, 0x3F, 0x00, 0x42}, // 2 Message right
{0xFF, 0x22, 0x38, 0x32, 0x3F, 0xE5, 0xB0}, // 3
{0xFF, 0x33, 0xE5, 0x4B, 0x3F, 0x4A, 0xEC}, // 4
{0xFF, 0x44, 0x99, 0x2A, 0x31, 0x12, 0x4A}, // 5
{0xFF, 0x01, 0x00, 0x04, 0x3F, 0x00, 0x44}, // 6 Message left
{0xFF, 0x55, 0x99, 0x4A, 0x5A, 0x3F, 0xD1}, // 7
{0xFF, 0x66, 0x8D, 0x38, 0x1E, 0x3F, 0x88}, // 8
{0xFF, 0x77, 0x5A, 0x3F, 0xA5, 0x8D, 0x42}, // 9
{0xFF, 0x88, 0x3F, 0x41, 0x80, 0x3F, 0xC7}, // 10
{0xFF, 0x01, 0x00, 0x08, 0x00, 0x3F, 0x48}, // 11 Message up
{0xFF, 0x99, 0xA5, 0xBB, 0x1E, 0xD5, 0xEC}, // 12
{0xFF, 0x0A, 0x88, 0x90, 0x00, 0x20, 0x42}, // 13
{0xFF, 0x02, 0x00, 0x14, 0x20, 0x00, 0x26}, // 14
{0xFF, 0x01, 0x00, 0x10, 0x00, 0x3F, 0x50} // 15 Message down
};
Serial1.write(bytes_to_send[index], 7);
//Serial << "Sending message nr: " << index+1 << endl;
if(++index == 15) index = 0;
//*/
// Data with errors =========================
const uint8_t bytes_to_send[] =
{
//start addr cmd1 cmd2 data1 data2 chcks
0xFF, 0x11, 0x1A, 0x5C, 0x6D, 0xEF, // 1 << ERROR, missing data
0xFF, 0x01, 0x00, 0x02, 0x3F, 0x00, 0x42, // 2 Valid: Message right
0xFF, 0x22, 0x38, 0x32, // 3 << ERROR, missing data
0xFF, 0x33, 0xE5, 0x4B, 0x3F, 0x4A, 0xEC, // 4 Valid
0xFF, 0x44, 0x99, 0x2A, 0x31, 0x12, 0xFF, // 5 << ERROR, 0xFF in message
0xFF, 0x01, 0x00, 0x04, 0x3F, 0x00, 0x44, // 6 Valid: Message left
0xFF, 0x55, 0x99, 0x4A, 0x5A, 0x3F, 0xD1, // 7 Valid
0x38, 0x1E, 0x3F, 0x88, // 8 << ERROR, missing data
0xFF, 0x77, 0x5A, 0x3F, 0xA5, 0x8D, 0x42, // 9 Valid
0xFF, 0x88, 0x3F, 0x41, 0x80, 0xFF, 0xC7, // 10 << ERROR, 0xFF in message
0xFF, 0x01, 0x00, 0x08, 0x00, 0x3F, 0x48, // 11 Valid: Message up
0xFF, 0x99, 0xA5, 0xBB, 0x1E, 0xD5, 0xEC, // 12 Valid
0xFF, 0x0A, 0xFF, 0x90, 0x00, 0x20, // 13 << ERROR, missing data 0xFF + 0x90, 0x00, 0x20, 0x02, 0x00, 0x14
0x02, 0x00, 0x14, 0x20, 0x00, 0x26, // 14 << ERROR, missing data combine to one 'valid' message
0xFF, 0x01, 0x00, 0x10, 0x00, 0x3F, 0x50 // 15 Valid: Message down
};
const size_t bytes_to_send_size = sizeof(bytes_to_send) / sizeof(bytes_to_send[0]);
Serial1.write(bytes_to_send[index]);
if(++index == bytes_to_send_size) index = 0;
//*/
} // End void transmit
RX code
#include <Streaming.h> // For serial debugging output - https://www.arduino.cc/reference/en/libraries/streaming/
/*
Arduino Nano Every Serial Ports:
(https://forum.arduino.cc/t/arduino-nano-every-access-to-4-serial/614358)
Serial -> USB interface
Serial1 -> D0 (RX) / D1 (TX) Stepper 1 PAN
Serial2 -> D7 (RX) / D2 (TX) Stepper 2 TILT
Serial3 -> D3 (RX) / D6 (TX) RS485 DATA
*/
// PELCO D MESSAGES ====================================
byte addr = 0x01; // Address of this receiving device
const int num_databytes = 6; // Number of data bytes in Pelco message
byte new_msg[num_databytes]; // Message array to store incoming bytes
byte new_msg_checksum = 0; // Byte to hold the checksum of a received message
/*=====================================
_____ ______ ______ __ __ ____
/ ___/ / ____//_ __// / / // __ \
\__ \ / __/ / / / / / // /_/ /
___/ // /___ / / / /_/ // ____/
/____//_____/ /_/ \____//_/
*/
void setup() {
Serial.begin(115200); // Hardware serial for debugging
Serial3.begin(4800); // Hardware serial data port
}
/*==============================
__ ____ ____ ____
/ / / __ \ / __ \ / __ \
/ / / / / // / / // /_/ /
/ /___/ /_/ // /_/ // ____/
/_____/\____/ \____//_/
*/
void loop() {
if(Serial3.available())
{
if(process_byte(Serial3.read()))
{
// A new message and checksum are ready to be read from:
// msg > byte new_msg[addr,cmd1,cmd2,dta1,dta2,chks] where chks is the checksum as received with the message
// The checksum calculated from addr,cmd1,cmd2,dta1,dta2 is stored in:
// chk > byte new_msg_checksum
byte ack[] = {0xFF, addr, 0x00, new_msg_checksum}; // ack message: start 0xFF, own address, alarm byte, calculated checksum
Serial3.write(ack, 4); // Write 4 bytes of ack over serial
// Up until this point in the code an ack with calculated
// checksum is sent back to the sending device to confirm reception
// For simple PT motor control only direction (R L U D)
// and the speed are needed, these messages are filtered out
/* Motor control messages, direction and speed
adrs cmd1 cmd2 dta1 dta2 chk
msg [0] [1] [2] [3] [4] [5]
right: 0x01, 0x00, 0x02, 0x##, 0x00, 0x## dat1 and dta2 can range from 0x00 to 0x3F
left: 0x01, 0x00, 0x04, 0x##, 0x00, 0x##
up: 0x01, 0x00, 0x08, 0x00, 0x##, 0x##
down: 0x01, 0x00, 0x10, 0x00, 0x##, 0x##
*/
switch(new_msg[2])
{
case 0x02:
Serial << " Go right at speed:" << new_msg[3] << endl;
break;
case 0x04:
Serial << " Go left at speed:" << new_msg[3] << endl;
break;
case 0x08:
Serial << " Go up at speed:" << new_msg[4] << endl;
break;
case 0x10:
Serial << " Go down at speed:" << new_msg[4] << endl;
break;
}
}
}
} // end loop
/*===============================================================================
____ ____ ____ ______ ______ _____ _____ ____ __ __ ______ ______
/ __ \ / __ \ / __ \ / ____// ____// ___// ___/ / __ )\ \/ //_ __// ____/
/ /_/ // /_/ // / / // / / __/ \__ \ \__ \ / __ | \ / / / / __/
/ ____// _, _// /_/ // /___ / /___ ___/ /___/ / / /_/ / / / / / / /___
/_/ /_/ |_| \____/ \____//_____/ /____//____/ /_____/ /_/ /_/ /_____/
*/
bool process_byte( byte recv_byte )
{
static int index = 0; // Index to place received bytes at
// Declared static to keep value between function calls
if (recv_byte == 0xFF)
{
index = 0; // A startbyte has been received, set index to zero
return false; // Return false for 'new message ready'
}
else
{
new_msg[index] = recv_byte; // Place receieved byte into message array
if ( ++index == num_databytes ) // After placing a byte at the last message array index,
{
index = 0; // reset the index to prevent 'out of index' error
// Checksum
new_msg_checksum = 0;
for(int i=0;i<=4;i++) new_msg_checksum += new_msg[i]; // The checksum is stored in a byte variable
// When summing only the 8 least significant bits will
// be left in this byte, overflow will be discarded
return true; // Return True to indicate a new message and checksum are ready to be read
}
return false; // A byte has been stored in new_msg[] but
} // new_msg[] is not yet complete and checked
}