Go Down

Topic: XBee Node Discovery problem (Read 1 time) previous topic - next topic

dhunt

I guess you could wait until there are enough bytes buffered in the serial buffer, but as PaulS pointed out the buffer is only 64 bytes in size and you run into danger of losing bytes if the buffer fills.

If I was doing this I would read in the header (which is only 3 bytes), get the length of the message from the header, then read in the body of the message. No need to hold your sketch up doing delays. For example (compiles but not tested):

Code: [Select]

#include "zb.h"

zb_message_t msg;

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

void loop()
{
    if (zigread(&msg) > 0) {
        Serial.println("Got a message");
    }
}

/* read in a zigbee message as it becomes available.
* When the full message is ready, return the size of the message.
* If the full message is not ready, return 0.
*/
int zigread(zb_message_t *msg)
{
    int data;
    static boolean waitingForHeader = true;
    static boolean gotFrameStart = false;
    static uint8_t bufInd = 0;
    static uint8_t checksum = 0;

    if (!gotFrameStart) {
       if (Serial1.available() && (Serial1.read() == ZB_FRAME_START)) {
          gotFrameStart = true;
       } else {
          /* Still waiting for start of frame */
          return 0;
       }
    }

    if (waitingForHeader) {
if (Serial1.available() < sizeof(zb_header_t)) {
    /* still waiting */
    return 0;
} else {
            /* read in the header */
    for (int ind=0; ind<sizeof(zb_header_t); ind++) {
((uint8_t *)msg)[ind] = Serial1.read();
    }
    /* fix up size */
    msg->header.length = ntohs(msg->header.length);

    /* time to start reading the body */
    waitingForHeader = false;
    bufInd = 0;
    checksum = msg->header.apiId;
}
    } else {
while (Serial1.available()) {
    data = Serial1.read();
    msg->payload[bufInd++] = (uint8_t)data;
    checksum += data;
    if (bufInd >= msg->header.length) {
/* Got the full message */
waitingForHeader = true;
gotFrameStart = false;

/* See if the checksum is correct */
checksum = 0xFF - checksum;
if (checksum == 0) {
    /* Good message, return size */
    return bufInd + sizeof(zb_header_t);
} else {
    /* Bad checksum, discard the message */
    Serial.println("Bad checksum");
    return 0;
}
    }
}
    }

    return 0; /* waiting for more data */
}


And zb.h is this:
Code: [Select]

#ifndef _ZB_H_
#define _ZB_H_

#include <Arduino.h>

/* convert network order uint16_t to host order */
#define ntohs(value) (((uint16_t)(value)) << 8 | (((uint16_t)(value)) >> 8))

#define ZB_MAX_PACKET_SIZE 128
#define ZB_FRAME_START 0x7e

typedef struct {
   uint16_t length; /* Length of payload including checksum */
   uint8_t apiId;
} zb_header_t;

typedef struct {
   zb_header_t header;
   uint8_t payload[ZB_MAX_PACKET_SIZE - sizeof(zb_header_t)];
} zb_message_t;

#endif

dhunt

<crickets chirping>

Okay maybe that was a bit ambitious.  Here's a simple version (compiles, not tested):

Code: [Select]

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

uint8_t msg[128];
uint8_t msgInd = 0; /* Current index into msg buffer */
uint8_t msgApi = 0; /* API of last received message */
int msgSize = -1; /* Size of message to receive */
boolean waitingNewMessage = true;

void loop()
{

    if (Serial1.available() > 0) {
        if (waitingNewMessage) {
    if (Serial1.read() == 0x7E) {
    /* Got start of frame */
waitingNewMessage = false;
msgInd = 0;
msgSize = -1;
    }
} else {
    if (msgSize < 0) {
    /* waiting to read message size and API */
if (Serial1.available() >= 3) {
    /* read in the two bytes for the message size */
    msgSize = Serial1.read() | ((int)Serial1.read()) << 16;

    /* Read in the message API */
    msgApi = Serial1.read();
}
    } else if (Serial1.available()) {
       /* Got another byte for the message buffer */

       /* Don't put too much data in the buffer */
       if (msgInd < sizeof(msg)) {
   msg[msgInd] = Serial1.read();
       }
       msgInd++;
    }
}
    }

    if (msgSize == msgInd) {
    /* Got a message */
waitingNewMessage = true; /* ready to start receiving the next message */
msgInd = 0;

/* deal with the message */
Serial.print("Got a message, ");
        Serial.print(msgSize);
        Serial.print(" bytes long");
    }
}


wwbrown

Thanks for the helpful hints.  I had some problems with the first code dhunt posted and came up with code similar to his second posted code.

After doing extensive programming in FORTRAN for the last 30 years doing numerical analysis and only dabbling in C when needed I am not fully comfortable with pointers and structures yet.

Thanks

wade

robcole

Hi Wade,
Please could you post your final sketch?

Go Up