differences with C on a PC

consider the following code, used to calculate a checksum of a series of bytes - this is related to my RS-485 question but from a slightly different angle

unsigned char crc8;
unsigned char i;
unsigned char srs[1024];
const unsigned char CRC8_LOOK_UP_TABLE[256] =
{
0x00,0x07,0x0e,0x09,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 
};
//Routine for the CRC
crc8= CRC8_LOOK_UP_TABLE [srs[0] ]; //first byte
// for incoming packet, data length is 9 byte, the routine should be should be looped for 7 times
// for outgoing packet, data length is 14 byte, the routine should be should be looped for 14 times for (i=1;i<=7;i++) //loop for 7 times for incoming packet
{
crc8= CRC8_LOOK_UP_TABLE [ crc8 ^ srs[i] ]; }

now on a PC this compiles and runs, my question is this, is there any reason it would produce a different answer on an Arduino?

it compiles and runs just fine, it seems to be working with 8 bit values only

wondering if there is something meaning the Arduino generates a different output to the Mac laptop which uses the same code and the end gizmo is just fine with it.

any thoughts?

usage is you put the data packet in the 'srs' array then iterate over the bits you need - the packets are only 9 bytes long though (not 1024)

Please post a complete Arduino sketch which shows the problem

this is the code being used

#include <SoftwareSerial.h>

// Tx pin 1 for hardware, 3 for software -- MAX485 DI
// Rx pin 0 for hardware, 2 for software -- MAX485 RO
// pin 8 for device select -- MAX485 DE & RE
// +5v & Ground to MAX485
// A & B to C7042 on V+ and V- (reversable)

// expected behaviour:
// comms to C7042 ok, pin 13 LED on constantly
// no comms back from C7042, pin 13 LED flashes twice then pauses before trying again

// test code to talk to the Scalextric C7042 powebase.
#define SS      // defines using the software serial library, comment out to use hardware UART

#ifdef SS
SoftwareSerial mySerial(2,3);
#endif

byte ReadBuffer[15] = {0};    // incoming bytes from the C7042
byte WriteBuffer[9] = {0};     // outgoing bytes to the C7042

unsigned char crc8;           // checksum for outgoing packet
unsigned char crc15;          // checksum for incoming packet, 15 bytes as we have updated the C7042
unsigned char srs[1024];      // not required
const byte CRC8_LOOK_UP_TABLE[256] =
{
0x00,0x07,0x0e,0x09,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 };


void setup() {
  // put your setup code here, to run once:

  Serial.begin(19200, SERIAL_8N1);    // set the baud rate for hardware serial port
  #ifdef SS
  mySerial.begin(19200);
  #endif 

  pinMode(13, OUTPUT);     // a pin to stick an LED on so we can see if this works or not on the Arduino
  pinMode(8, OUTPUT);

  // flash the LED on then off before proceeding as a test, on then off
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
  byte CRC8;

  // calc the first packet to send to the C7042

  WriteBuffer[0] = 0xFF;   // operation mode
  // drive packet is 1's compliment
      // bit 0-5 = speed 0-63
      // bit 6 = lane change, 1 = change lane, 0 = don't
      // bit 7 = brake, 1 = brake on, 0 = brake off
  WriteBuffer[1] = 0xFF;      // car 1
  WriteBuffer[2] = 0xFF;      // car 2
  WriteBuffer[3] = 0xFF;      // car 3
  WriteBuffer[4] = 0xFF;      // car 4
  WriteBuffer[5] = 0xFF;      // car 5
  WriteBuffer[6] = 0xFF;      // car 6 - should drive at about half speed
  WriteBuffer[7] = B11000001;    // LEDs, start the track then show "101010" on the red LEDs
  // calc checksum byte
  // first operation: 
  CRC8 = CRC8_LOOK_UP_TABLE [WriteBuffer[0] ];
  // then loop over the est of the data
   for (byte i=1;i<=7;i++) //loop for 7 times for packet to the C7042, 13 times for the packe from the C7042
   {
     CRC8 = CRC8_LOOK_UP_TABLE [ CRC8 ^ WriteBuffer[i] ]; 
   }
   WriteBuffer[8] = CRC8;

}

void loop() {
  // put your main code here, to run repeatedly:

  // see if the C7042 is talking to us

  size_t R;

  // write the pre-prepared packet out
  digitalWrite(8, HIGH);    // set RS485 DE & RE to HIGH to write
  #ifdef SS
  R = mySerial.write(WriteBuffer, sizeof(WriteBuffer));
  mySerial.flush();           // wait for the message to actually send
  #else
  R = Serial.write(WriteBuffer, sizeof(WriteBuffer));
  Serial.flush();           // wait for the message to actually send
  #endif
  digitalWrite(8, LOW);     // set RS485 DE & RE to LOW to listen

  //delay(10);

  R = mySerial.available();

  #ifdef SS
  if (R >= 15)
  {
    // we have a packet, read it byte by byte into the array
    for (byte C = 0; C <15; C++)
    {
      ReadBuffer[C] = mySerial.read();
    }
  }
  #else
  // read back, 15 bytes from the firmware updated C7042
  //R = Serial.readBytes(ReadBuffer, sizeof(ReadBuffer));  
  #endif


  // note we don't do anything with what comes back

  if (R != 15)
  {
    // no data and we timed out
    // flash the LED, thus flashing LED == Error of some sort or no response from the C7042
    delay(250);
    digitalWrite(13, HIGH);
    delay(250);
    digitalWrite(13, LOW);
    delay(250);
    digitalWrite(13, HIGH);
    delay(250);
    digitalWrite(13, LOW);
  }
  else
  {
    // just put the light on
    digitalWrite(13, HIGH);
  }

  delay(1000);    // wait a short time before trying again

}

this generates a fixed packet of 8 bytes, sticks the checksum on the end and sends it - via software serial or hardware serial (to an RS-485 that sends it on) - the hardware side is a side issue, suffice it to say on that it will send happily to another arduino that can decode the packet quite happily

we then send the packet out, wait a bit to see what comes back, currently nothing comes back and I'm wondering if this is due to the checksum code coming to the wrong value

currently nothing comes back

When there is an Arduino as the receiver? Or when the real device is receiving the data?

If nothing comes back from the Arduino as receiver, what is that Arduino telling you it is doing, and where is its code?

If the Arduino returns data, but the other device doesn't, the problem is not with the sending Arduino.

another Arduino sees the code and replies quite happily, which suggests the serial link is working.

my issue is that another Arduino will calculate the checksum the same way, and get the same answer.

I'm wondering if the code would produce a different answer on an Arduino than say a PC?

I don't see why it would, the operations are all pretty standard.

I'm just trying to rule out a few issues

I'm wondering if the code would produce a different answer on an Arduino than say a PC?

It's trivial to answer that question. We'll wait...

I'm just trying to rule out a few issues

If I write a letter, and mail it to my grandmother, and I get a reply, I'm not going to blame my pen, the paper, or the postal carrier if I write another letter and send it to a different address, if I don't get a reply.

I can't see why you are doing that.

code for the listening Arduino

unsigned char ReadBuffer[9] = {0};
unsigned char WriteBuffer[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

void setup() {
  // put your setup code here, to run once:

  Serial.begin(19200, SERIAL_8N1);    // set the baud rate

  pinMode(13, OUTPUT);     // a pin to stick an LED on so we can see if this works or not on the Arduino
  pinMode(8, OUTPUT);

  // flash the LED on then off before proceeding as a test
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);

}

void loop() {
  // put your main code here, to run repeatedly:

  // we should be sent 9 bytes
  digitalWrite(8, LOW);   // listen

  byte R = 0;
  R = Serial.available();    // how many bytes do we have?

  if (R >= 9) 
  {
    R = Serial.readBytes(ReadBuffer, sizeof(ReadBuffer));

    // we read up to nine bytes into the buffer
    // we now stop listening and send our 15 byte response
    digitalWrite(8, HIGH);
    Serial.write(WriteBuffer, sizeof(WriteBuffer));
    Serial.flush();
    digitalWrite(8, LOW);

    digitalWrite(13, HIGH);

  }
  else
  {
    //digitalWrite(13, LOW);
  }
 
}

all it does is see if its sent 9 bytes, read them in, then send 15 bytes back, its purpose was just to test the RS-485 link - have varied it to blink its LED to show various things, number of bytes seen, the value of one or other of the bytes etc.

if it works as presented the LED comes on and stays on, the other Arduino shows if it gets 15 bytes back

What is the point of calculating a CRC value, if the receiver doesn't use it?

because the actual C7042 powebase this is going into does, hence the question really that will an Arduino produce a different result via that calculation than say a PC would - I don't see why it would, indeed I don't overly see how it could given there are only 8 bit bytes used so should be no 'endian' issues to worry about (I hope)

as I understand it the CRC is used to accept or reject the data packet as valid or gibberish

in the test code between the arduinos all one does is send 8 bytes, with a 9th as a CRC to the other, without caring what the values are, and all the other does is say "yup, 9 bytes seen, have 15 back", which is then repeated.

the nine bytes being sent are related to the control information, basically telling the base this is a command (1st byte), what six slot cars should do (next six bytes) and what LEDs it has it should light up (8th byte) - the data being sent instructs it to keep all six cars stationary but light half the LEDs just so I can see that something has happened.

as I see it there are three things here:

  • the format of the data
  • the serial link (there is another question about that aspect elsewhere, but since two Arduino can talk the hardware works, the only outstanding issue is the configuration)
  • the value of the checksum

I have this working from a laptop, I'd just like to leave the laptop at home and replace it with a nice cheap, but perfectly serviceable Arduino that I can then also use to do other related functions - like a start grid lights etc

so I know the format of the data is valid, I know the serial hardware works (and it should be configured correctly), its just the checksum I'm wondering about

the C7042 uses the same checksum format when it replies, assuming I can get it to reply, which currently it won't so (though it can be ignored if you accept slot cars occasionally embedding themselves in the wall or a passing cat)

I have incidentally tried with other bits of code calculating the CRC at the listening Arduino end to see if it gets the same as it was sent (same method, process the first 8 bytes, then compare with the 9th it was sent). that works but then its two identical boards running identical calculations so I wasn't overly surprised by this

its infuriating, and its likely something very obvious thats stopping it working but I can't see it so trying to eliminate things step by step

given the Arduino can count and can handle the ^ operator there is no reason for the code not to work.. but there are far wiser heads here so worth asking

hence the question really that will an Arduino produce a different result via that calculation than say a PC would

That is something you could test.

Hint: if the results are different, the two programs are not equivalent.

jremington:
That is something you could test.

Hint: if the results are different, the two programs are not equivalent.

yes, yes I could, and the parts needed to do it are on order (RJ-12 socket so I can plug the laptops output dongle into the Arduino to see exactly what it spits out with a view to replaying it to the serial monitor in hex format

I just need to wait for the bits to arrive, and yes if the results are different the code is different.

The reason for asking the question was to see if anyone knew a reason why they could be different when calculated on different hardware using the same code, and this while I wait for the bits that I need for something else anyway but can borrow for this first.

As a matter of course, people calculate the same CRC from the same data using different hardware. All the time!

The entire point of a CRC is to verify correct data transmission from one machine to another. It is not foolproof, though.

You simply need to verify how to do that properly on both machines.

why they could be different when calculated on different hardware using the same code,

Different sizes of the datatypes?
Some platforms implement char as signed, others unsigned; some implement int as sixteen bit, others thirty-two

jremington:
As a matter of course, people calculate the same CRC from the same data using different hardware. All the time!

The entire point of a CRC is to verify correct data transmission from one machine to another. It is not foolproof, though.

You simply need to verify how to do that properly on both machines.

Indeed, hence using the code from the device interface specification to try and do just that, and hence the question here to see if there was anything obvious that could lead to the same code producing a different answer and thus the code needing modifying in some way

TheMemberFormerlyKnownAsAWOL:
Different sizes of the datatypes?
Some platforms implement char as signed, others unsigned; some implement int as sixteen bit, others thirty-two

this was the sort of thing I was wondering, the spec specifically calls for "unsigned char" to get the basic byte data type

pondering if "unsigned char" is being resolved as something else, or resolved as something else differently to how say a PC (or Mac in this case) would do it. you may well be on to something here, will have a fiddle and see what I can do.

annoyingly I can't currently get XCode to fire up to adjust or experiment with the mac code I wrote a few years back but I can still run it and it works.

very much food for thought, my thanks

tried re-compiling with the 'unsigned char' in the spec as 'byte', didn't make a difference but was worth a try.

also tried sticking a delay in after transmission to see if that helps (i.e. wait a bit for a response before checking), a much faster PC didn't need it but no harm in trying.

had a check of the code the laptop runs and thats using unsigned char as well

back to head scratching and next step is to see what the laptop writes out and compare with what the Arduino writes out and go from there

"byte" is a nonstandard Arduino invention, to be avoided.

To be relatively sure of common variable sizes on different machines, I use the standard definitions from <stdint.h>, e.g. uint8_t, etc.

jremington:
"byte" is a nonstandard Arduino invention

...and almost guaranteed to confuse anyone used to the Java "byte" datatype, which is signed.
Truly incomprehensible

TheMemberFormerlyKnownAsAWOL:
...and almost guaranteed to confuse anyone used to the Java "byte" datatype, which is signed.
Truly incomprehensible

that is a bit weird..

it fair enough, I grew up with 8 bit machines where bytes were what you had, and occasional posh people had "words" with all sorts of weird and wonderful lengths

I tend to use byte here because its a darn sight easier to type and say than "uint8_t", even if perhaps less 'specific'

still needs must etc, will try to stick to uint8_t in future, generally I use whatever the function I'm working withs documentation says to use

only fair to post this back.

hardware arrived to validate this, the software application on the mac that works sends its initial 9 byte packet out as thus:

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x6D

the 0x6D being the calculated checksum in question

the Arduino given the same eight bytes produced the following 9 byte packet

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0x6D

identical, also the Arduino picked up the laptop - C7042 transmission correctly first time so presumably the serial port configuration is also correct.

result of that is the assumption that the software is correct, and the serial port software configuration is correct so its something irritating in the Hornby hardware that wants the hardware side slightly different before it will listen

however, many thanks for the help and guidance here