Sending structured packets over Serial from Arduino

Hi Everyone,

This is my first post here, so first of all, hello world.

I’m fairly new to serial comms but I’ve succeeded in some basic command outputs.

I’m having problems trying to send structured data packets from my Arduino UNO to an Atomos Samurai video recording device which has a serial remote control input. I have a data sheet for the serial protocol, which I have attached, but I will copy the key info into my post here.

I have my UNO serial going through a MAX485 board to convert my serial commands to RS485, and I have my USB logic analyser attached to the output of the MAX485. I can successfully send individual bytes using the following code:

const int enable = 4;  // set enable command output pin to 4

void setup(){

  pinMode(enable, OUTPUT); // 'enable' set as output 
  Serial.begin(9600);
}


void loop() {

  digitalWrite(enable, HIGH); // set as 'enable' high 

  delay(10);
  Serial.write(0x14); // sends '0x14' in hex

}

This works fine, and returns a ‘0x14’ every second on my logic analyser sample. However, I need to send a structured packet from the UNO, with a CRC attached. More specifically, in this format:

Packet Structure
The packet is variable length with BIG endian data ordering which has a minimum length of 16 bytes and a maximum length of 24 bytes.

Size 2 bytes Total size of the packet in bytes INCLUDING the 4-byte CRC appended to the data.
Command 2 bytes Command id or status id.
Address 8 bytes Client address (unit name) or SERIAL_COMMAND_BROADCAST_ADDRESS.
Data Packet data, zero or more bytes with the caveat that it must be in multiples of 4 bytes.
CRC 4 bytes 16-bit CRC of entire packet. An example in C is given in Appendix B.

The datasheet gives an example for sending a simple broadcast ‘record’ command in C, as follows:

s8 data[0x14] =
{
  0x00, 0x14,
  0x00, 0x00,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0x00, 0x00, 0x00, 0x01,
  0x00, 0x00, 0x00, 0x00,
};

u32 len = sizeof(data);
u32 crc = crc_16((const u8*)data, len - sizeof(u32));
*(u32*)(data + len - sizeof(u32)) = SWAP_U32(crc);

serial_write(serial, data, len);

Now I know C is pretty closely related to Aduino-speak, but I’m really not expert enough to make my UNO send this sort of data packet. That’s where I’d like some advice if anyone would be so kind as to help.

How can I send a structured packet of data like this from my Arduino UNO? Is it possible/worthwhile writing a CRC calculation script or should I just calculate it beforehand and stick it on the back end of each command? I only need to send four commands to the unit - Record, Stop, Touchscreen Lock and Touchscreen Unlock. I don’t mind manually (via online calculator ;)) calculating the CRC for each of those.

Any advise very much appreciate.

samurai_serial_remote_control.doc (149 KB)

Regarding the CRC you should have a look at the libraries that come with the IDE (AVR-GCC compiler libraries).

http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html

Note, that you will need to have “#include <util/crc16.h>” at the top of your sketch to use them.

When you say “I can successfully send individual bytes using the following code:…” does this mean that the remote unit is sending back the right acknowledgement? I suspect it isn’t as there is no CRC attached to your packet and the remote will view it as corrupt.

I used the following sketch as a proof of concept when I started using CRCs:

#include <util/crc16.h>

void setup()
{
  Serial.begin(9600);
  delay(3000);
  Serial.println("Calculating...");
  Serial.print(checkcrc());
}

uint8_t serno[] = { 0x02, 0x1c, 0xb8, 0x01, 0, 0x55, 0, 0xa2 };
//uint8_t serno[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
//uint8_t serno[] = {"The cat sat on the mat"};

uint16_t checkcrc(void)
{
  uint16_t crc = 0;
  uint8_t i;
  for (i = 0; i < sizeof serno / sizeof serno[0]; i++)
  {
    crc = _crc16_update(crc, serno[i]);
  }
  //Serial.println(crc);
  return crc; 
}

void loop()
{
}

For radio transmisions I use structures to construct the data packet. Some snippets of code are below:

struct DataPacket
{
  uint8_t PacketID;
  uint8_t To;
  uint8_t From;
  uint8_t SourceAddress;
  uint8_t DestinationAddress;
  uint8_t Type;
  uint8_t Payload;  
  uint16_t CRC;
}

.....
.....
....
// make up the packet

              DataPacket TxPacket;
              TxPacket.PacketID = random(250);
              TxPacket.To = xxxxxxx;
              TxPacket.From = xxxxxxx;
              TxPacket.SourceAddress = xxxxxx;
              TxPacket.DestinationAddress = xxxx;
              TxPacket.Type = xxxxxx;
              TxPacket.Payload = xxx                          
               TxPacket.CRC = MakeCRC(&TxPacket);


//Then transmit the whole structure.
........
.......
........

uint16_t MakeCRC(struct DataPacket *InPacket)
{
  uint16_t TempCRC = 0;
  TempCRC = _crc16_update(TempCRC, InPacket->PacketID);
  TempCRC = _crc16_update(TempCRC, InPacket->To);
  TempCRC = _crc16_update(TempCRC, InPacket->From);
  TempCRC = _crc16_update(TempCRC, InPacket->SourceAddress);
  TempCRC = _crc16_update(TempCRC, InPacket->DestinationAddress);
  TempCRC = _crc16_update(TempCRC, InPacket->Type);
  TempCRC = _crc16_update(TempCRC, InPacket->Payload);
  return TempCRC;
}

Hi lemming,

Thank you for your reply. When I said about successfully sending individual bytes, I just meant I can generate them from the UNO’s Tx. I haven’t got to the stage of plugging in the Atomos device yet. My creations were just single bytes going to my logic analyser - not CRCd so wouldn’t have been of use anyway. I’m having to take baby-steps as this is quite new to me.

I have read through the CRC library manual you linked and also through the code you sent. I am keen to progress to that stage, and I do understand quite a bit of it. It’s well past my sleep time, so my brain is a bit slow on the uptake, but I’m desperate to crack this. I can see that you use uint8_t, which I think is so that you can ascertain it’s length for the CRC calculation yes?

In the time between my posting the question and your reply, I did manage to get my UNO to send out a packet of data which I think is getting close to what the Atomos wants (see attached). I did this with some very rough and ready code, and using an online calculator to calculate the CRC (might be wrong…?). Could you please have a quick look and see if you think this represents the requirements of Atomos that I posted in my original question? I’m new to serial comms so a little unsure of what I’m supposed to be looking for. I’m not to fussed with what the Atomos recorder sends back to the Arduino - I just want to tell it to record etc, and let it get on with it. This will be one way communication from UNO to Atomos (shouting orders, if you will ;))

Here’s the code I used to get the attached logic sample:

const int enable = 4;  // set enable command output pin to 4

void setup(){
  pinMode(enable, OUTPUT); // 'enable' set as output 
  Serial.begin(9600);
}

void loop() {
  digitalWrite(enable, HIGH); // set as 'enable' high 
  delay(1000);

  Serial.write(0x00);
  Serial.write(0x14);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0x01);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0x00);
  Serial.write(0xCF);
  Serial.write(0x1C);
}

I don't think you need to add another CRC, since there is one in the structure already, and it looks like you have the code to generate it.

As for endianness. It would help to know what types the elements of the struct are.

Length is an int (in Arduino terms), but with opposite endianness.
Command is probably an int.
Address is ??? string perhaps. If so endianness likely does not enter into it.
Data is unknown. You'd probably know better than I would, what has to be sent.
CRC looks like an unsigned long, though again with opposite endianness.

Here's a little chunk of code to extract the parts of an int. I tested it with 0x14 first, then used decimal 13731 to get non-zero values for both nybbles of the high order byte. As you can see, I printed the second byte of the int first, and the first byte second, making it high-endian order.

You can do the same thing with the CRC, for example, by sending the data of the byte array equivalent as 3, 2 , 1, 0.

void setup() {
  Serial.begin (57600);
  int foo = 13731;
  byte  *fooaddr;
  fooaddr  = (byte *)&foo;
  Serial.println(foo);
  Serial.println(foo, HEX);
  Serial.println(fooaddr[1]);
  Serial.println(fooaddr[0]);
  Serial.println(fooaddr[1], HEX);
  Serial.println(fooaddr[0], HEX);
}

void loop() {
}

Hello

I' am new here, my name is peter and my english is not so good =( but I hope you can help.
Do you have success with the arduino and atomos ? Does the application work ?
I' am in the same situation. I would like to remote the Atomos over RS-485.
My Hardware should be a C-Control, programm language is Basic. I know this is not state of the art but I wrot some programms and all works fine with this.
If your System work please be so kind and let me know the code. I only need Record start and Record Stop for the Atomos.
Last question : Which RS232 to RS485 Adapter you use.
kind regards
Peter

Dear all,

Same here, I have a Atomos Samurai and really need a remote control for my line of work (wildlife video). Has anyone succeeded in making this RS485 adaptor and can give me some hints?

I took the manual 'Serial Remote Control Specification Revision 1.7' to a guy who makes small computers and programmes them in Arduino but knows C as well, but he says it is not very clear how one should translate the instructions into code. Furthermore, It says that you should put the Atomos device in 'remote', and I don't find this on my Samurai. I tried to read everything I could find about this problem, but so far, I cannot find a solution.

I would be gratefull if someone could help me out.

Thanks,

Rollin

Rollin:
I took the manual 'Serial Remote Control Specification Revision 1.7' to a guy who makes small computers and programmes them in Arduino but knows C as well, but he says it is not very clear how one should translate the instructions into code. Furthermore, It says that you should put the Atomos device in 'remote', and I don't find this on my Samurai. I tried to read everything I could find about this problem, but so far, I cannot find a solution.

That guy had a huge advantage over us folks here - he could read the book and figure out what you are talking about.

If you seriously want help you need at least to post a link to the instruction manual so we can read it.
A link to the datasheet for the Atomos Samurai (whatever that is) would also be a big help.

...R

Dear Robin,

I apologize for the misunderstanding. It is the same document as the first poster attached. It is also the only reference on the internet of this document.

Concerning the Atomos itself, here is a link to the manual, but the only reference to this problem is on page 16, and I quote “Samurai Blade Start and Stop record control can be triggered by the following methods: 6. via the LANC serial port
Controlled by a third party computer or controller. For system and OEM integration, contact support@atomos.com”.

But no reaction yet. I guess they will send me the document the first poster attached.

Kind regards,

Rollin

Rollin:
I apologize for the misunderstanding. It is the same document as the first poster attached. It is also the only reference on the internet of this document.

OK. I will look at it later. I was not involved with this Thread before I saw your post.

...R

I have no had time for a quick look at the datasheet linked in the first post of this Thread.

My first thought is that there are two issues - the hardware connection and the commands to send over the link - and I'm not sure which part is causing you a problem.

I confess I know nothing about RS485 (beyond how to spell it) but, as far as I know it can be interfaced to an Arduino with suitable hardware. No doubt Google can help. The first Post mentions a max485 chip.

I can't figure out from all of the earlier posts what the Atomos Samurai does and why people want to control it with an Arduino. A sentence of two of general explanation would be useful.

...R

Thanks for looking at my problem.

An Atomos Samurai is a video recorder. If one wants to film with his photocamera, in my case a Nikon D800, the compression of the footage is very high, so it can fit on a memory card. There is a way to work around this, using the HDMI output which has more quality and capture this data with an external device like an Atomos. Unfortunately, this thing only has a touch-screen. It can be controlled by a standard named Lanc, but only with dedicated camera's, not Nikon. So something has to be built which can control the Atomos via this Lanc, something that mimics (I suppose) a real videocamera.

There are lanc remote controls, but for some reason, Atomos has decided to use only lanc in loop. A standard remote control does not answer I guess, while a videocamera does.

Rollin:
An Atomos Samurai is a video recorder. ...

That is helpful, but you didn't answer my other questions.

...R

I speak Dutch first, then French and my third language is English. That is the reason I guess why I see no other questions in your post than "what is a an Atomos, and why build a remote?".

The reason why one could use Arduino for this, is that the only reference on the internet to build a remote controller for the Atomos, is this topic on an Arduino forum.

If you have more questions, please, be more specific. I do my best to elaborate about my problem, but my knowledge of the possible solution is limited.

I hoped to find someone who used the instructions to build an actual adaptor and could help me built one myself. But I understand now that I don't have to put much hope in that.

Rollin:
I see no other questions in your post than "what is a an Atomos, and why build a remote?".

This is the piece that you did not respond to

My first thought is that there are two issues - the hardware connection and the commands to send over the link - and I'm not sure which part is causing you a problem.

I can try to help, but you are correct - I have not done it before.

...R

Thank you for the clarification.

I will ask my friend to study the document again, and if he has specific questions, I will ask you for help. Otherwise, I just take more time of you.

For now, I thank you for your interest in my problem.

Kind regards,

Rollin

Hi, i want to make the same thing except i use a MSP430 µcontroler to control my atomos Samurai blade ( it’s a recorder) But it doesn’t work for me.

I want to control the samurai Blade to start a recording (with lanc port and protocol atomos)

i use the same programm than ardvino ( in the document : Serial Remote Control Specification )
i use a MAX485 to convert my UART signal in RS 485.

I send with 9600 bauds the data in this order :

0x00, 0x14,
0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01,
0xfd, 0xf5, 0x00, 0x00,

my CRC = 0xf5fd and it swap like this with swap_u32(CRC)

With one Start bit and one Stop bit for every bytes

But my atomos doesn’t recognize this message.

Can you confirm that the message i have to send for recording is correct ?

And Can you confirm that my CRC = 0xf5fd is correct ? by using this function :

u32 crc = crc_16((const u8*)data, len - sizeof(u32)); (same programm than ardvino )

If someone have the timing diagram of the record command ?

It would be very nice if someone can help me

Sorry for my english

samurai_serial_remote_control.doc (149 KB)