2014年10月24日金曜日

Arduino で遊ぼう(3) XBeeとシリアル接続してAPIモード

Arduino とXBee wifiをシリアルで接続して、APIモードで動かしました。

XBee wifiにはtelnetで接続すると、
受信パケットをエコーバックします。

シリアルのボーレートは57600bpsまでしかうごきませんでした。

とりあえずのコード
(汚い…、。)

/*
 XBee WiFi Connected Serial.
 XBee works in API Mode.

 Receie Serial and Parse API packet,
 then echo back by API packet.
 */

/**
 * 送信パケットの生成
 */
int makeXBeeApiSendIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrDst, byte* pbPortDst, byte* pbPayload, word length)
{
if(u16Size < length + 16)
{
Serial.println("buffer too short");
return -1;
}

// パケット生成
pPacket[0] = 0x7E;
// length
        u16Size = length + 12;
pPacket[1] = u16Size >> 8;
pPacket[2] = u16Size & 0x00FF;
// API Cmd
pPacket[3] = 0x20;
// FrameID
pPacket[4] = 0x00;
// IpAddrDst
pPacket[5] = pbIpAddrDst[0];
pPacket[6] = pbIpAddrDst[1];
pPacket[7] = pbIpAddrDst[2];
pPacket[8] = pbIpAddrDst[3];
// PortDst
pPacket[9] = pbPortDst[0];
pPacket[10] = pbPortDst[1];
// PortSrc
pPacket[11] = 0x26;
pPacket[12] = 0x16;
// Packet Type
pPacket[13] = 0x01; //< TCP, Connection Keep
//
pPacket[14] = 0x00;
// Payload
for(int i=0; i<length; i++)
{
pPacket[15 + i] = pbPayload[i];
}
// チェックサム計算
byte sum = 0;
for(int i=0; i<length + 12; i++)
{
sum += pPacket[3 + i];
}
pPacket[length + 15] = 0xFF - sum;

return length + 16;
}

/**
 * 受信パケットのダンプ
 */
void printPayload(byte* pPayload, word length)
{
  if(0 < length)
  {
    Serial.println("dump");
for(word i = 0; i<length; i++)
{
Serial.print(pPayload[i], HEX);
Serial.print(",");
}
        Serial.println();
  }
}

/**
 * 受信パケットのパース
 */
byte g_pbIpAddrSrc[4];
byte g_pbPortSrc[2];
byte* g_pbPayload;
int parseXBeeApiReceiveIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrSrc, byte* pbPortSrc, byte** ppbPayload) {
// APIコード確認
if (0xB0 != pPacket[3]) {
// Serial.print("wrong api code:");
// Serial.println(pPacket[3]);
return -1;
}
// 送信元IPアドレス取得
pbIpAddrSrc[0] = pPacket[4];
pbIpAddrSrc[1] = pPacket[5];
pbIpAddrSrc[2] = pPacket[6];
pbIpAddrSrc[3] = pPacket[7];
//        Serial.write(pbIpAddrSrc, 4);
//        Serial.println();
// 送信元ポート取得
pbPortSrc[0] = pPacket[10];
pbPortSrc[1] = pPacket[11];
//        Serial.write(pbPortSrc, 2);
//        Serial.println();
// ペイロード取得
*ppbPayload = &pPacket[14];

//        Serial.println(pPacket[1]);
//        Serial.println(pPacket[2]);

return ((int) pPacket[1] << 8) + (int) pPacket[2] - 11;
}

/**
 * 受信処理
 */
#define RECEIVE_IP 1
unsigned char u8ReceiveMode = 0;
#define RECEIVE_MODE_IDLE 0
#define RECEIVE_MODE_LEN1 1
#define RECEIVE_MODE_LEN2 2
#define RECEIVE_MODE_DATA 3
#define RECEIVE_MODE_CS 4
#define APIPACKET_SIZE_MAX 1024
byte g_pu8ApiPacket[APIPACKET_SIZE_MAX];
unsigned short g_u16ApiPacketSize;
unsigned short g_u16ApiPacketLength;
int parseChar(byte data) {
// Serial.println(data, HEX);

switch (u8ReceiveMode) {
case RECEIVE_MODE_IDLE:
// wait for "0x7E"
if (0x7E == data) {
g_u16ApiPacketSize = 0;
g_u16ApiPacketLength = 0;
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN1;
// Serial.println("api start");
}
break;
case RECEIVE_MODE_LEN1:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN2;
break;
case RECEIVE_MODE_LEN2:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_DATA;
g_u16ApiPacketLength = ((unsigned short) g_pu8ApiPacket[1] << 8)
+ (unsigned short) g_pu8ApiPacket[2];
// Serial.print("get len :");
// Serial.println(g_u16ApiPacketLength);
if (g_u16ApiPacketLength > (APIPACKET_SIZE_MAX - 4)) {
Serial.println("invalid data len");
u8ReceiveMode = RECEIVE_MODE_IDLE;
}
break;
case RECEIVE_MODE_DATA:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
if ((g_u16ApiPacketSize - 3) >= g_u16ApiPacketLength) {
u8ReceiveMode = RECEIVE_MODE_CS;
// Serial.println("get data");
}
break;
case RECEIVE_MODE_CS:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_IDLE;
// Serial.println("get cs");
return RECEIVE_IP;
break;
default:
break;
}
return 0;
}

byte RXLED = 13;
byte toggle = 0;

void setup() {
pinMode(RXLED, OUTPUT);  // Set RX LED as an output
// TX LED is set as an output behind the scenes

Serial.begin(115200); //This pipes to the serial monitor
Serial1.begin(4800); //This is the UART, pipes to sensors attached to board
}

void loop() {
if (0 < Serial.available()) {
                byte data = Serial.read();
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
if (0 == toggle) {
digitalWrite(RXLED, LOW);   // set the LED on
TXLED0; //TX LED is not tied to a normally controlled pin
toggle = 1;
} else {
digitalWrite(RXLED, HIGH);    // set the LED off
TXLED1;
toggle = 0;
}
}
if (0 < Serial1.available()) {
// Serial.write(parseChar(Serial1.read()));
if (RECEIVE_IP == parseChar(Serial1.read())) {
int len = parseXBeeApiReceiveIp(g_pu8ApiPacket, g_u16ApiPacketSize,
g_pbIpAddrSrc, g_pbPortSrc, &g_pbPayload);
Serial.print("receive ip packet:");
Serial.println(len);

printPayload(g_pbPayload, len);

// echo
                        byte data = *g_pbPayload;
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
}
}
}

0 件のコメント:

コメントを投稿