Monday, November 1, 2010

First Packet Test

The Arduino sends test packets to  processing which decodes them on screen

IMG_3087

Code after the jump

Arduino Code
//protocol.h
//Device Codes

#define DVC_LM33           0x01
#define DVC_ST11           0x02
#define DVC_ST15           0x03
#define DVC_DOORCONTACT    0x04
#define DVC_FLIPSWITCH     0x05
#define DVC_LIGHT          0x06
#define DVC_MOTION         0x07
#define DVC_2LINECHAR      0x08
#define DVC_POWER30        0x08
#define DVC_POWER100       0x09
#define DVC_SMARTOUTLET    0x10
#define DVC_RGBLIGHT       0x11

//Command Codes

#define CMD_GET_VERSION    0x01
#define CMD_PING           65
#define CMD_PONG           0xE3

#define CMD_ACK            0x11

#define CMD_READ           0xAA
#define CMD_WRITE          0xBB

#define CMD_PORTTYPE       0xCC

#define CMD_AUTOSENDSTART  0xC1
#define CMD_AUTOSENDSTOP   0xC2

#define CMD_ERROR          0xFF

//@todo commands for different data types?

//decoded packet struct
typedef struct {
  uint8_t command;
 //if 255 = ready to send // 0 = resend last
  uint8_t length;
  uint8_t sent;
  uint8_t settings; //01010101 //version //type direct or broadcast //ack //ttl //priority //multi
  uint8_t type; //1 single tcp, 2 single udp, 3 multipacket tcp
  uint16_t fromNode;
  uint8_t fromPort;
  uint16_t toNode; //00 is base //xffff is broadcast
  uint8_t toPort;
  uint8_t id;
  uint8_t ttl;
  
  uint8_t payload[48];
  uint16_t checksum;
  uint8_t ptr;
} DataPacketDecoded;


//simple data packet
typedef struct {
  uint8_t ptr;
  uint8_t sent;
  uint8_t payload[56];
  uint16_t checksum;
} DataPacket;

//shortcuts to important bytes
//keeps from having to decode the whole thing to check simple parts
#define PACKET_LENGTH   0
#define PACKET_SETTINGS 1
#define PACKET_FROM     2
#define PACKET_TO       4
#define PACKET_TTL      4
#define PACKET_ID       6
#define PACKET_COMMAND  7
#define PACKET_PAYLOAD  8


//send_test_packet.pde
#include h> //checksum functions
#include "protocol.h"

#define NODE_ID 0x02

#define PORT_A DVC_LM33
#define PORT_B DVC_LM33
#define PORT_C DVC_LM33
#define PORT_D DVC_LM33

#define PACKET_BUFFER 4 //can be adujsted based on availbe space

#define debug 1;

//types
//ACK
//Single TCp //requires 2byte packet ID
//Single UDP
//Multi TCP //requires 2byte total ID, 2 byte Packet ID + byte current packet + byte total packets
//multi packet
//packet id
//current packets
//total packets
//

DataPacket data[PACKET_BUFFER];
DataPacketDecoded dataDecoded[2];
byte dataPtr = 0;
uint16_t checksum;
byte dataId = 0;
byte packetIds = 0;
byte uniqueId = 0;
byte i;
DataPacket incomingPacket; //current incoming packet
//incomingPacket.ptr = 0;

byte getNewPacketId() {
  for(i=0; i < PACKET_BUFFER; i++) {
    if(data[i].payload[PACKET_SETTINGS] == 0){
      return i;
    } 
  }
}

byte getId() {
  return uniqueId++; //what happens when this overflows?
}

uint16_t compressAddress(uint16_t node, uint8_t port) 
{
  return (node << 4) | (port & 0x0F);
}


boolean send_packet_serial(uint8_t packetId)
{
  uint16_t dataChecksum = 0;
  for(i=0; i < (data[packetId].payload[PACKET_LENGTH]-2); i++){
    dataChecksum = _crc16_update(dataChecksum, data[packetId].payload[i]);
    Serial.print(data[packetId].payload[i],BYTE);
    // Serial.print(",");
  } 
  data[packetId].status = 1;
  data[packetId].checksum = dataChecksum;
  //Serial.println("");
 // Serial.print("checksum: ");
  //Serial.print(dataChecksum,BYTE);

  //Serial.print("checksum: ");
  Serial.print(highByte(dataChecksum),BYTE);
 // Serial.print(",");
  Serial.print(lowByte(dataChecksum),BYTE);//*/
   
}

uint8_t build_tcp_packet(uint16_t fromNode, uint8_t fromPort, uint16_t toNode, uint8_t toPort, uint8_t command, uint8_t payload[48], uint8_t length)
{
  byte packetId = getNewPacketId();
  data[packetId].status = 0;
  data[packetId].payload[PACKET_LENGTH] = length + 10; //header 8 crc 2
  data[packetId].payload[PACKET_SETTINGS] = 1;
  uint16_t address = compressAddress(fromNode, fromPort);
  data[packetId].payload[PACKET_FROM] = highByte(address);
  data[packetId].payload[PACKET_FROM+1] = lowByte(address);
  address = compressAddress(toNode, toPort);
  data[packetId].payload[PACKET_TO ] = highByte(address);
  data[packetId].payload[PACKET_TO+1] = lowByte(address);
  data[packetId].payload[PACKET_ID] = getId();
  data[packetId].payload[PACKET_COMMAND] = command;
  
  for(i=0;i < length;i++){
    data[packetId].payload[PACKET_PAYLOAD+i] = payload[i];
  }

  return packetId;
}
byte build_udp_packet(uint16_t fromNode, uint8_t fromPort, uint16_t toNode, uint8_t toPort, uint8_t command, uint8_t payload[48], uint8_t length)
{
  byte packetId = getNewPacketId();
  data[packetId].status = 0;
  data[packetId].payload[PACKET_LENGTH] = length + 10;
  data[packetId].payload[PACKET_SETTINGS] = 2;
  uint16_t address = compressAddress(fromNode, fromPort);
  data[packetId].payload[PACKET_FROM] = highByte(address);
  data[packetId].payload[PACKET_FROM+1] = lowByte(address);
  address = compressAddress(toNode, toPort);
  data[packetId].payload[PACKET_TO ] = highByte(address);
  data[packetId].payload[PACKET_TO+1] = lowByte(address);
  data[packetId].payload[PACKET_ID] = getId();
  data[packetId].payload[PACKET_COMMAND] = command;
  
  for(i=0;i < length;i++){
    data[packetId].payload[PACKET_PAYLOAD+i] = payload[i];
  }
  return packetId; 
}

uint8_t build_broadcast_packet(uint16_t fromNode, uint8_t fromPort, uint16_t toNode, uint8_t toPort, uint8_t payload[48], uint8_t length, uint8_t ttl )
{
  byte packetId = getNewPacketId();
  data[packetId].status = 0;
  return packetId;
}

void process_command(DataPacketDecoded packet)
{
  switch (packet.command) {
    case CMD_PING:

      //replyPacket.payload = packet.payload;
      //replyPacket.command = CMD_PONG;
      //replyPacket.fromNode = NODE_ID;
      //send_packet(packet);
      break;
    default:
      //send_packet(COMMAND_ERROR,NULL,0);
      break;
    }
}

/**
 * turns a packet into a decoded packet
 */

DataPacketDecoded decode_packet(DataPacket packet)
{
  DataPacketDecoded decodedPacket;
     
  decodedPacket.ttl = 0;
  
  //Set Packet length
  decodedPacket.length = packet.payload[PACKET_LENGTH];
  
  decodedPacket.status = packet.status;
  
  //settings 
  decodedPacket.settings = packet.payload[PACKET_SETTINGS];
  decodedPacket.type = packet.payload[PACKET_SETTINGS]; //right now these are the same things


  //From 12bit node id, 4 bit plug id
  decodedPacket.fromNode = packet.payload[PACKET_FROM];
  decodedPacket.fromNode = decodedPacket.fromNode << 4;
  decodedPacket.fromNode = decodedPacket.fromNode | (packet.payload[PACKET_FROM+1] >> 4);
  decodedPacket.fromPort = packet.payload[PACKET_FROM+1] &0xF;
  
  //To 12bit node id, 4 bit plug id
  decodedPacket.toNode = packet.payload[PACKET_TO];
  decodedPacket.toNode = decodedPacket.toNode << 4;
  decodedPacket.toNode = decodedPacket.toNode | (packet.payload[PACKET_TO+1] >> 4);
  decodedPacket.toPort = packet.payload[PACKET_TO+1] &0xF;

 //packet id
  decodedPacket.id = packet.payload[PACKET_ID];

 //Command
  decodedPacket.command = packet.payload[PACKET_COMMAND];
  
  decodedPacket.ptr = packet.payload[PACKET_LENGTH] - 8;
   
  for(i=PACKET_PAYLOAD; i < (packet.payload[PACKET_LENGTH] - 2); i++){

    if(decodedPacket.type < 3) { //single packet TCP or UDP
        
          decodedPacket.payload[i-PACKET_PAYLOAD] = packet.payload[i];   
     
    } else if(decodedPacket.type == 3) {  //broadcast
        //todo
    }
  }
  decodedPacket.checksum=packet.checksum;
  return decodedPacket;
}

void build_incoming_packet(uint8_t bIn)
{
  if(incomingPacket.ptr == 0){  //Packet length
    if(bIn == 0) {
    //resend last
    return;
    }
    if(bIn == 255) {
      //aknowledge
      //delete packet from que
      //reset last pointer
      return;
    }
    if (bIn > 128) {
      //stop sending current packet
      //flush
      return;
    }
    incomingPacket.payload[PACKET_LENGTH] = bIn;
    uint16_t temp;
    checksum = 0;
  }
  
  //checksum 
  if(incomingPacket.ptr < incomingPacket.payload[PACKET_LENGTH]){ //add to check sum
    incomingPacket.payload[incomingPacket.ptr] = bIn;
    checksum = _crc16_update(checksum, bIn);
  } else if(incomingPacket.ptr == incomingPacket.payload[PACKET_LENGTH]){ //get first byte of checksum
    incomingPacket.checksum = bIn;
  } else { //get second byte and check the checksum
    incomingPacket.checksum = (incomingPacket.checksum << 8) | bIn;         
    if(checksum != incomingPacket.checksum) {
      //Serial.println(checksum, DEC);  
      //Serial.println(incomingPacket.checksum, DEC);   
      //Serial.println("Failed CRC Check"); 
      incomingPacket.ptr=0;
    } else {
      i = getNewPacketId();
      data[i] = incomingPacket;
      incomingPacket.ptr=0;
    }
  }
  
  incomingPacket.ptr++;

}

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

void loop() {
  
  byte message[1] = {uniqueId};
  int sendPacketId =  build_udp_packet(NODE_ID, 1, 0, 0, CMD_PING, message, 1);

  
  send_packet_serial(sendPacketId);

  delay(2000);
      
        
}

Processing Code
//Device Codes

final int DVC_LM33          = 0x01;
final int DVC_ST11          = 0x02;
final int DVC_ST15          = 0x03;
final int DVC_DOORCONTACT   = 0x04;
final int DVC_FLIPSWITCH    = 0x05;
final int DVC_LIGHT         = 0x06;
final int DVC_MOTION        = 0x07;
final int DVC_2LINECHAR     = 0x08;
final int DVC_POWER30       = 0x08;
final int DVC_POWER100      = 0x09;
final int DVC_SMARTOUTLET   = 0x10;
final int DVC_RGBLIGHT      = 0x11;

//Command Codes

final int  CMD_GET_VERSION   = 0x01;
final int  CMD_PING          = 65;
final int  CMD_PONG          = 0xE3;
final int  CMD_ACK           = 0x11;
final int  CMD_READ          = 0xAA;
final int  CMD_WRITE         = 0xBB;
final int  CMD_PORTTYPE      = 0xCC;

final int  CMD_AUTOSENDSTART = 0xC1;
final int  CMD_AUTOSENDSTOP  = 0xC2;

final int  CMD_ERROR         = 0xFF;




class DataPacketDecoded {
  int command, length, status = 0, settings, type,  fromPort, toPort, id, ttl = 0, ptr = 0;
  int fromNode, toNode,  checksum = 0;
  int[] payload = new int[56];

  DataPacketDecoded() {
   
  }
  
 
}


//simple data packet

class DataPacket {
  int ptr = 0, status = 0, checksum = 0;
  int[] payload = new int[64];
  
  DataPacket() {
  }
} 


//shortcuts to important bytes
//keeps from having to decode the whole thing to check simple parts
final int PACKET_LENGTH   = 0;
final int PACKET_SETTINGS = 1;
final int PACKET_FROM     = 2;
final int PACKET_TO       = 4;
final int PACKET_TTL      = 4;
final int PACKET_ID       = 6;
final int PACKET_COMMAND  = 7;
final int PACKET_PAYLOAD  = 8;

int _crc16_update(int crc, int a)
{
    int i;
    crc ^= a;
    for (i = 0; i < 8; ++i){
        if ((crc & 1) == 1){
            crc = (crc >> 1) ^ 0xA001;
        }else{
            crc = (crc >> 1);
        }
    }
    return crc & 0xFFFF;
}

int getId() {
  return uniqueId++; //what happens when this wraps?
}

int compressAddress(int node, int port) 
{
  node = node << 4; //make space
  port = port & 0x0F;
  return node | port;
}




import processing.serial.*;

//What should master ports be?

final int  NODE_ID = 0x02;

final int PORT_A = DVC_LM33;
final int PORT_B = DVC_LM33;
final int PORT_C = DVC_LM33;
final int PORT_D = DVC_LM33;

DataPacket data[];

int dataPtr = 0;
int checksum;
int dataId = 0;
int packetIds = 0;
int uniqueId = 0;
int i;

DataPacket incomingPacket = new DataPacket(); //current incoming packet

int bgcolor;        // Background color
int fgcolor;        // Fill color
Serial myPort;                       // The serial port
int[] serialInArray = new int[3];    // Where we'll put what we receive
int serialCount = 0;                 // A count of how many bytes we receive

boolean firstContact = false;        // Whether we've heard from the microcontroller
PFont myFont;

void setup() {
  size(400, 400);  // Stage size
  //noStroke();      // No border on the next thing drawn
  myFont = createFont("Consolas", 14);
  textFont(myFont);
  

  // Print a list of the serial ports, for debugging purposes:
  //println(PFont.list());

  String portName = Serial.list()[1];
  myPort = new Serial(this, portName, 115200);
}

void draw() {
  
   //text("Hello",10,10);
   //text("Z", 10, 220);
   
  // Draw the shape

}

void serialEvent(Serial myPort) {
  // read a byte from the serial port:
  int inByte = myPort.read();
  build_incoming_packet(inByte);
}

//#include  //checksum functions



boolean send_packet_serial(DataPacket packet)
{
  int dataChecksum = 0;
  for(i=0; i < (packet.payload[PACKET_LENGTH]-2); i++){
    dataChecksum = _crc16_update(dataChecksum, packet.payload[i]);
    myPort.write(packet.payload[i] & 0xFF);
  } 
  packet.status = 1;
  myPort.write(dataChecksum & 0xFFFF); 
  return true;
}

DataPacket build_tcp_packet(int fromNode, int fromPort, int toNode, int toPort, int command, int payload[])
{
  DataPacket packet = new DataPacket();
  //packet.payload[PACKET_LENGTH] = length + 8;
  packet.payload[PACKET_SETTINGS] = 1;
  int address = compressAddress(fromNode, fromPort);
  packet.payload[PACKET_FROM] = (address >> 8) & 0xFF;
  packet.payload[PACKET_FROM+1] = address & 0xFF;
  address = compressAddress(toNode, toPort);
  packet.payload[PACKET_TO ] = (address >> 8) & 0xFF;
  packet.payload[PACKET_TO+1] = address & 0xFF;
  packet.payload[PACKET_ID] = getId();
  packet.payload[PACKET_COMMAND] = command;
  
  for(i=0;i < payload.length;i++){
    packet.payload[PACKET_PAYLOAD+i] = payload[i];
  }

  return packet;
}
DataPacket build_udp_packet(int fromNode, int fromPort, int toNode, int toPort, int command, int payload[])
{
  DataPacket packet = new DataPacket();
  //packet.payload[PACKET_LENGTH] = length + 8;
  packet.payload[PACKET_SETTINGS] = 2;
  int address = compressAddress(fromNode, fromPort);
  packet.payload[PACKET_FROM] = (char)(address >> 8) & 0xFF;
  packet.payload[PACKET_FROM+1] = (char)address & 0xFF;
  address = compressAddress(toNode, toPort);
  packet.payload[PACKET_TO ] = (char)(address >> 8) & 0xFF;
  packet.payload[PACKET_TO+1] = (char)address & 0xFF;
  packet.payload[PACKET_ID] = getId();
  packet.payload[PACKET_COMMAND] = command;
  
  for(i=0;i < payload.length;i++){
    packet.payload[PACKET_PAYLOAD+i] = payload[i];
  }
  return packet; 
}
/*
uint8_t build_broadcast_packet(uint16_t fromNode, uint8_t fromPort, uint16_t toNode, uint8_t toPort, uint8_t payload[48], uint8_t length, uint8_t ttl )
{
  byte packetId = getNewPacketId();
  data[packetId].sent = 0;
  return packetId;
}
*/
void process_command(DataPacketDecoded packet)
{
  switch (packet.command) {
    case CMD_PING:

      //replyPacket.payload = packet.payload;
      //replyPacket.command = CMD_PONG;
      //replyPacket.fromNode = NODE_ID;
      //send_packet(packet);
      break;
    default:
      //send_packet(COMMAND_ERROR,NULL,0);
      break;
    }
}

/**
 * turns a packet into a decoded packet
 */

DataPacketDecoded decode_packet(DataPacket packet)
{
  DataPacketDecoded decodedPacket = new DataPacketDecoded();
       
  //Set Packet length
  decodedPacket.length = packet.payload[PACKET_LENGTH];
  
  decodedPacket.status = packet.status;
  
  //settings 
  decodedPacket.settings = packet.payload[PACKET_SETTINGS];
  decodedPacket.type = packet.payload[PACKET_SETTINGS]; //right now these are the same things


  //From 12bit node id, 4 bit plug id
  decodedPacket.fromNode = packet.payload[PACKET_FROM];
  decodedPacket.fromNode = decodedPacket.fromNode << 4;
  decodedPacket.fromNode = decodedPacket.fromNode | (packet.payload[PACKET_FROM+1] >> 4);
  decodedPacket.fromPort = packet.payload[PACKET_FROM+1] &0xF;
  
  //To 12bit node id, 4 bit plug id
  decodedPacket.toNode = packet.payload[PACKET_TO];
  decodedPacket.toNode = decodedPacket.toNode << 4;
  decodedPacket.toNode = decodedPacket.toNode | (packet.payload[PACKET_TO+1] >> 4);
  decodedPacket.toPort = packet.payload[PACKET_TO+1] &0xF;

 //packet id
  decodedPacket.id = packet.payload[PACKET_ID];

 //Command
  decodedPacket.command = packet.payload[PACKET_COMMAND];
  decodedPacket.checksum = packet.checksum;
  decodedPacket.ptr = packet.payload[PACKET_LENGTH] - 10;
   
  for(i=PACKET_PAYLOAD; i < packet.payload[PACKET_LENGTH]; i++){

    if(decodedPacket.type < 3) { //single packet TCP or UDP
        
          decodedPacket.payload[i-PACKET_PAYLOAD] = packet.payload[i];   
     
    } else if(decodedPacket.type == 3) {  //broadcast
        //todo
    }
  }
  return decodedPacket;
}

void build_incoming_packet(int bIn)
{
  //add timout to reset if packets get jamed
  println("count: "+incomingPacket.ptr + " byte: " + bIn);
  if(incomingPacket.ptr == 0){  //Packet length
    if(bIn == 0) {
      //resend last
      return;
    }
    if(bIn == 255) {
      //aknowledge
      //delete packet from que
      //reset last pointer
      return;
    }
    if (bIn > 66) {
      //stop sending current packet
      //flush
      return;
    }
    incomingPacket.payload[PACKET_LENGTH] = bIn;
    println("length: "+bIn);
    checksum = 0;
  }

  //checksum 
  if(incomingPacket.ptr < (incomingPacket.payload[PACKET_LENGTH]-2)){ //add to check sum
    incomingPacket.payload[incomingPacket.ptr] = bIn;
    checksum = _crc16_update(checksum, bIn);

  } else if(incomingPacket.ptr == (incomingPacket.payload[PACKET_LENGTH]-2)){ //get first byte of checksum

    incomingPacket.checksum = bIn;
  } else { //get second byte and check the checksum
    incomingPacket.checksum = (incomingPacket.checksum << 8) | (bIn & 0xFF); 
     
    if(checksum != incomingPacket.checksum) {
      println("processing checksum: " + checksum);  
      println("    packet checksum: " + incomingPacket.checksum);   
      println("Failed CRC Check"); 
    } else {
      println("processing checksum: " + checksum);  
      println("    packet checksum: " + incomingPacket.checksum);  
     println("Passed CRC Check");  
      debug_incoming_packet(incomingPacket);
      //check packet address, if it matches, process command, if not add to queue to resend to other nodes
      //i = getNewPacketId();
      //data[i] = incomingPacket;
      //process_command(incomingPacket);
      
      //incomingPacket = DataPacket;
    }
    //reset incoming packet
    incomingPacket = new DataPacket();
    return;
  }

  incomingPacket.ptr++;
}

void debug_incoming_packet(DataPacket packet) 
{
  background(0);
  println("show packet info");
  text("Packet Info",5,15);
  int x = 20;
  DataPacketDecoded packetDecoded = decode_packet(packet);
  text("  status: " + packetDecoded.status,10,x+=20);
  text("  length: " + packetDecoded.length,10,x+=20);
  text("settings: " + packetDecoded.settings,10,x+=20);
  text("    type: " + packetDecoded.type,10,x+=20); 
  text("fromNode: " + packetDecoded.fromNode,10,x+=20);
  text("fromPort: " + packetDecoded.fromPort,10,x+=20);
  text("  toNode: " + packetDecoded.toNode,10,x+=20);
  text("  toPort: " + packetDecoded.toPort,10,x+=20);
  text("     ttl: " + packetDecoded.ttl,10,x+=20);
  text("      id: " + packetDecoded.id,10,x+=20);
  text(" command: " + packetDecoded.command,10,x+=20);
  
  String message = "";
  for(i=0; i < packetDecoded.ptr; i++){
    message += int(packetDecoded.payload[i]);
    //message += char(packetDecoded.payload[i]);
  } 
  text(" payload: " + message,10,x+=20);
  
  text("checksum: " + packetDecoded.checksum,10,x+=20);
  text("     ptr: " + packetDecoded.ptr,10,x+=20);//*/
}

No comments:

Post a Comment