Arrays Function Parameters Mess

Hi gals & guys,
I have something like this:

void Ltbl::loop(){
switch(_state){
[…]
case Opened:
byte commandChannel = readCommand();
[…]
else {
handleLightUpdate(commandChannel);
}
break;
}
}

void Ltbl::handleLightUpdate(byte commandChannel){
int buffer[7];
pollPort(7, buffer);
int channels = buffer[0];
blink(channels);
int red = word(buffer[1], buffer[2]);
int green = word(buffer[3], buffer[4]);
int blue = word(buffer[5], buffer[6]);
light(red,green,blue);
}

void Ltbl::pollPort(int bytes, int buffer){
while(Serial.available() < bytes){
delay(10);
}
for(int i=0; i < bytes; i++){
buffer = Serial.read();

  • }*
    }[/font]
    If I use a simple debug routine (blink - blinks the onboard LED the specified number of times) inside the pollPort Function I receive the correct number. Yet the int Array inside the handleLightUpdate contains gibberish - not the same values as in PollPort function. I tried passing & references and * pointers but without any success. What am I doing wrong? :’(

Are you aware that serial data transmission follows the United States Postal Service contract? The USPS guarantees to try to deliver the mail on time. They do not guarantee to deliver it on time.

Serial data can get lost. Your code for reading serial data assumes that no data ever gets lost.

Yet the int Array inside the handleLightUpdate contains gibberish - not the same values as in PollPort function.

How do you know this? There are no Serial.print() statements in either routine, so how do you know that the array doe not contain the same information in both functions?

Hi Paul,
thanks for your quick response. Sure I am fully aware of the Serial “contract”. The read command does contain some logic for finding the proper byte sequences - and sure my loop and handleLightUpdate need some error handling for dropped or delayed bytes. Yet I am a pragmatic programmer and I am still working on my tracer bullet use case before I harden everything.

I refrained from using Serial.println() statements as I didn’t want to have duplex serial handling - as mentioned in the previous post I use my little blink function:

void Ltbl::blink(int count){
for(int i=0; i<count;i++){
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
}
delay(200);
}

If I have blink(buffer[0]) in the last line of the pollPort function, the led blinks 3 times - as I expect from the serial input. If I add the statement blink(channels) in the handleLightUpdate function after the line int channels = buffer [0] the led blinks dozens/hundreds of times.

I strongly assume this has something to do how arrays are passed between functions.

The read command does contain some logic for finding the proper byte sequences

void Ltbl::pollPort(int bytes, int buffer[]){
 while(Serial.available() < bytes){
   delay(10);
 }
 for(int i=0; i < bytes; i++){
   buffer[i] = Serial.read();
 }
}

Where is this logic? All this code is doing is grabbing the next 7 bytes, once there are 7 bytes to grab.

If whatever is sending data sends 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13…, and the 5 gets lost, how will your read function know that?

What is sending data?

Hi Paul,
thanks again for your quick reply, I hope you are aware that you are forcing me in a defensive stance with your persistent questions about lost bytes - even though I am asking about a different problem. I am implementing a client for the LTBL protocol (http://blogger.xs4all.nl/loosen/articles/420470.aspx), which uses logical packages with a 2 byte header. As mentioned the readCommand function, checks this - here is the checkFor function which is used by the readCommand function:

boolean Ltbl::checkFor(byte bytes, int arraySize){
if(Serial.available() >= arraySize){
byte firstByte = Serial.read();
if(firstByte == bytes[0]){
for(int i = 1; i < arraySize; i++){
if(Serial.peek() == bytes*){*

  • Serial.read();*
  • }*
  • else {*
  • return false; //peeked value did not match*
  • }*
  • }*
  • return true; //read all values correctly*
  • }*
  • else {*
  • return false; // first value did not match*
  • }*
  • }*
  • else {*
  • return false;//not enough values to read*
  • }*
    }
    [/font]
    This function ensures that one byte is always popped from the buffer, as soon as the header is out of sync, it tries again with the next byte, otherwise it checks for the entire header and returns true if applicable for further handling. This ensures that I pick up at the next package / command once a byte is lost during transmission - currently I am happing that I will have a bad package read sometimes, as long as it continues to work afterwards.
    I will gladly open a new thread in which you can enlighten me with additional insights on serial data handling.
    But I would like to shine the light of expertise at the problem given to me currently. The blink function returns different values for the same buffer entry, depending if the function is invoked in the “reading” function or from the “calling” function. In both cases the data has already been read from Serial so timing can be excluded as a potential cause.
    Regards
    Stefan

I needed to know what was sending the data, to determine the feasibility of using Serial.print() to see the contents of array, in both functions. It does not appear to be feasible, so I will quit asking about that.

If you change the pollPort function definition to

void Ltbl::pollPort(int bytes, int &buffer[])

does the problem persist?

Hi Paul, I thought about this, but I found this here: http://stackoverflow.com/questions/1106957/pass-array-by-reference-in-c claiming that any array function argument is passed by reference to the first element per definition in C. Is this link correct?

Nonetheless if I try your idea, I get this error:

error: declaration of 'buffer' as array of references

Any idea what I am doing wrong? Sorry for my C ignorance.

Stefan

I tried this:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  test();
}

void test()
{
  int stuff[7];
  readPort(7, stuff);
  for(int i=0; i<7; i++)
  {
    Serial.print("stuff[");
    Serial.print(i);
    Serial.print("} = ");
    Serial.println(stuff[i]);
  }
}

void readPort(int size, int array[])
{
  while(Serial.available() < size)
  {
  }
  
  for(int i=0; i<size; i++)
  {
    array[i] = Serial.read();
  }
  
  for(int i=0; i<size; i++)
  {
    Serial.print("array[");
    Serial.print(i);
    Serial.print("} = ");
    Serial.println(array[i]);
  }
}

I opened the serial monitor, typed “ABCDEFGHIJKLMNOPQRSTUVWXYZ”, pressed Send, and got this:

array[0} = 65
array[1} = 66
array[2} = 67
array[3} = 68
array[4} = 69
array[5} = 70
array[6} = 71
stuff[0} = 65
stuff[1} = 66
stuff[2} = 67
stuff[3} = 68
stuff[4} = 69
stuff[5} = 70
stuff[6} = 71
array[0} = 72
array[1} = 73
array[2} = 74
array[3} = 75
array[4} = 76
array[5} = 77
array[6} = 78
stuff[0} = 72
stuff[1} = 73
stuff[2} = 74
stuff[3} = 75
stuff[4} = 76
stuff[5} = 77
stuff[6} = 78
array[0} = 79
array[1} = 80
array[2} = 81
array[3} = 82
array[4} = 83
array[5} = 84
array[6} = 85
stuff[0} = 79
stuff[1} = 80
stuff[2} = 81
stuff[3} = 82
stuff[4} = 83
stuff[5} = 84
stuff[6} = 85

I think your problem must lie elsewhere.

Stefan, can you post your whole code? (please use the # button to add code tags)

I would at least add this one to your lib to prevent active waiting aka blocking :)

int LTBL::PeekPort()
{
  return Serial.available();
}

From http://blogger.xs4all.nl/loosen/articles/420470.aspx The LTBL protocol uses a two byte prefix of 0x55 0xAA, then one byte which sets the startchannel if it's from 0 to 126, or a command if it's 127 or above. The next byte sets the number of channels sent, or the number of bytes in case of a command. Then the data is sent, for channel data it uses two bytes per channel so you can use up to 16 bit pwm. It sends the most significant byte first

This means that a package could look as follows

PREFIX      | START  | NR OF CHAN | 2 BYTES PER CHANNEL 
0x55   0xAA | 0x00   |  0x03      | 0x00 0x00 0x00 0x00 0x00 0x00 

or

PREFIX      | CMD  | START  | NR OF CHAN  
0x55   0xAA | 0x81 | 0x00   | 0x03

So why are you reading 7 bytes ? what packet do you expect?