This is an experimental driver for the XBee 900 HP pro module's SPI connection. This driver is unfinished and stability is not guaranteed. Use with caution.

Dependents:   Sentinel_BASE Sentinel_NODE

xbee900hp.cpp

Committer:
ottaviano3
Date:
2016-04-27
Revision:
15:3bb82129f3a8
Parent:
9:d4542525b218

File content as of revision 15:3bb82129f3a8:

#include "xbee900hp.h"

xbee900hp::xbee900hp(PinName pin_mosi,PinName pin_miso,PinName pin_sck,PinName pin_attn, PinName pin_rst, unsigned int freq)
    : _pin_rst(pin_rst), _pin_attn(pin_attn), _xbeespi(pin_mosi,pin_miso,pin_sck) {
    // Set proper spi transfer mode format.
    _xbeespi.format(8,0);
    // Set SPI frequency
    _xbeespi.frequency(freq);

    // Reset for good measure.
    reset();

    // Xbee is up and running!
}

xbee900hp::~xbee900hp() {}

void xbee900hp::reset()
{
    _pin_rst = 0;
    // Minimum pulse is 1ms
    wait_ms(2);
    _pin_rst = 1;
    
    // Wait for device to have time to start the reboot process.
    wait_ms(80);

    // Now wait for the startup message.
    while (attn() == 1) {}

    // This is the message the XBEE should send out on startup after a reset.
    unsigned int modemMsg[6] = { 0x7E,0x00,0x02,0x8A,0x00,0x75 };
    // Container for or new message.
    unsigned int delim[6];

    // Read in the new message from the xbee.
    for (int i = 0; i < 6; i++) {
        delim[i] = _xbeespi.write(0x00);
    }

    // Compare recieved msg with msg we want.
    if (memcmp(delim, modemMsg, sizeof(modemMsg))) {
        // If msg mismatch.
        error("XBEE FAILURE");
    }
}

int xbee900hp::sendPacket(char* data, unsigned int length, bool enMesh) {
    // checksum
    unsigned int checksum;
    unsigned int checksumsub = 0;

    // start char
    _xbeespi.write(0x7E);
    // lenght
    _xbeespi.write(0x00);

    unsigned int totallength = 14 + length - 1;
    _xbeespi.write(totallength);

    // frame delimter
    _xbeespi.write(0x10);
    checksumsub += 0x10;
    // id for later reference
    _xbeespi.write(0x00);

    // destination address
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);
    _xbeespi.write(0xFF);
    checksumsub += 0xFF;
    _xbeespi.write(0xFF);
    checksumsub += 0xFF;

    // reserved field, dont change
    _xbeespi.write(0xFF);
    checksumsub += 0xFF;
    _xbeespi.write(0xFE);
    checksumsub += 0xFE;

    //bcast radius
    _xbeespi.write(0x00);

    // This is a bitmasked field
    // bit 0: Disable ACK
    // bit 1: Disable Route Discovery
    // bit 2: Enable Unicast NACK messages.
    // bit 3: Enable Unicast Trace Route messages.
    // bits 6,7: b’01 - Point-Multipoint
    //          b’10 - Repeater mode (directed broadcast)
    //          b’11 - DigiMesh
    // All other bits must be set to 0.
    if (enMesh == true) {
        // Transmit using digimesh
        _xbeespi.write(0xC0);
        checksumsub += 0xC0;
    } else {
        // Transmit point to point (without ACK)
        _xbeespi.write(0x41);
        checksumsub += 0x41;
    }

    // dat data
    for (int i = 0; i < (length - 1); i++) {
        _xbeespi.write(*data);
        checksumsub += (*(data++));
    }

    // Calculate checksum
    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // finally write checksum
    _xbeespi.write(checksum);

    return 0;
}

unsigned long long xbee900hp::readPacket(char* data) {
    unsigned long long temp1;
    unsigned int temp2;
    
    unsigned long long srcAddr = 0;

    unsigned int checksumsub = 0;
    unsigned int checksum;

    // get first vars.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x7E) {
        return 0;
    }
    // Get length of message
    temp1 = _xbeespi.write(0x00);
    temp2 = _xbeespi.write(0x00);

    // Get total length
    unsigned int length = (temp1<<8) | temp2;

    // Next read frame type to ensure it is an RX packet.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x90) {
        return 0;       
    }
    checksumsub += temp1;

    // in our case we dont care about source address this should be modified to extract source address if needed.
    temp1 = _xbeespi.write(0x00);
    srcAddr = (temp1 << 56);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 48);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 40);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 32);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 24);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 16);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1 << 8);
    checksumsub += temp1;
    temp1 = _xbeespi.write(0x00);
    srcAddr ^= (temp1);
    checksumsub += temp1;
    // reserved field, we dont care about except for checksum
    checksumsub += _xbeespi.write(0x00);
    checksumsub += _xbeespi.write(0x00);

    // recive options we also dont care though
    checksumsub += _xbeespi.write(0x00);

    // Now for the sweet sweet data.
    for (int i = 0; i<(length-12); i++) {
        *data = _xbeespi.write(0x00);
        checksumsub += *(data++);
    }
    // Null terminate char array.
    *data = '\0';

    // Get that salty checksum
    temp1 = _xbeespi.write(0x00);

    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // Check the checksum
    if (temp1 != checksum) {
        // Checksum failure, flag to discard packet
        return 0;
    }

    return srcAddr;
}

int xbee900hp::attn() {
    return _pin_attn;
}

unsigned int xbee900hp::getRSSI() {
    // checksum Variables
    unsigned int checksum = 0;
    unsigned int checksumsub = 0;

    // RSSI storage container
    unsigned int rssi;

    // Frame initiator
    _xbeespi.write(0x7E);
    // Length
    _xbeespi.write(0x00);
    _xbeespi.write(0x04);

    // Frame type (config)
    _xbeespi.write(0x08);
    checksumsub += 0x08;
    // Response frame ID
    _xbeespi.write(0x44);
    checksumsub += 0x44;

    // AT Command
    _xbeespi.write(0x44); // Hex for ASCII D
    checksumsub += 0x44;
    _xbeespi.write(0x42); // Hex for ASCII B
    checksumsub += 0x42;

    // Calculate checksum
    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // finally write checksum
    _xbeespi.write(checksum);

    // Block until xbee replys
    while (_pin_attn != 0) { }

    // reset checksum to zero.
    checksum = 0;
    checksumsub = 0;

    unsigned int temp1;
    unsigned int temp2;

    // get start byte
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x7E) {
        // drop packet
        return 1;
    }
    // Get length of message (we dont care, we know what it is)
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);

    // Next read frame type to ensure it is an response packet.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x88) {
        // drop packet
        return 0;
    }
    checksumsub += temp1;

    // get response frame id

    while (temp1 != 0x44) {
        // Dredge through data until the response frame we want arrives.
        temp1 = _xbeespi.write(0x00);
    }
    checksumsub += temp1;

    // get at response parameter
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;

    if ((temp1 != 0x44) || (temp2 != 0x42)) {
        return 1;
        // drop
    }

    // Check OK flag
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x00) {
        return 1;
        // drop
    }
    checksumsub += temp1;

    // Get RSSI Data
    rssi = _xbeespi.write(0x00);
    checksumsub += rssi;

    // Get that salty checksum
    temp1 = _xbeespi.write(0x00);

    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // Check the checksum
    if (temp1 != checksum) {
        // Checksum failure, flag to discard packet
        return 1;
    }

    return rssi;
}

int xbee900hp::setPower(int value) {
    if ((value > 4) || (value < 0)) {
        return 1;
    }

    // checksum Variables
    unsigned int checksum = 0;
    unsigned int checksumsub = 0;

    // Frame initiator
    _xbeespi.write(0x7E);
    // Length
    _xbeespi.write(0x00);
    _xbeespi.write(0x05);

    // Frame type (config)
    _xbeespi.write(0x08);
    checksumsub += 0x08;
    // Response frame ID
    _xbeespi.write(0x50);
    checksumsub += 0x50;

    // AT Command
    _xbeespi.write(0x50); // Hex for ASCII P
    checksumsub += 0x50;
    _xbeespi.write(0x4C); // Hex for ASCII L
    checksumsub += 0x4C;

    // Value to set
    _xbeespi.write(value);
    checksumsub += value;

    // Calculate checksum
    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // finally write checksum
    _xbeespi.write(checksum);

    // Block until xbee replys
    while (_pin_attn != 0) { }

    // reset checksum to zero.
    checksum = 0;
    checksumsub = 0;

    unsigned int temp1;
    unsigned int temp2;

    // get start byte
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x7E) {
        // drop packet
        return 1;
    }
    // Get length of message (we dont care, we know what it is)
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);

    // Next read frame type to ensure it is an response packet.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x88) {
        // drop packet
        return 0;
    }
    checksumsub += temp1;

    while (temp1 != 0x50) {
        // Keep going through data until response frame is found.
        temp1 = _xbeespi.write(0x00);
    }
    checksumsub += temp1;

    // get at response parameter
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;

    if ((temp1 != 0x50) || (temp2 != 0x4C)) {
        return 1;
        // drop
    }

    // Check OK flag
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x00) {
        return 1;
        // drop
    }
    checksumsub += temp1;

    // Get that salty checksum
    temp1 = _xbeespi.write(0x00);

    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // Check the checksum
    if (temp1 != checksum) {
        // Checksum failure, flag to discard packet
        return 1;
    }

    return 0;
}

unsigned long long xbee900hp::getSerial() {
    // checksum Variables
    unsigned int checksum = 0;
    unsigned int checksumsub = 0;

    // Container for serial as we calculate it.
    unsigned long long serialNumber = 0;

    // Containers for read values
    unsigned long long temp1 = 0;
    unsigned long long temp2 = 0;
    unsigned long long temp3 = 0;
    unsigned long long temp4 = 0;

    // Write frame to return serial high.
    // Total frame looks like this:
    // 7E 00 04 08 52 53(S) 48(H) CHECKSUM
    // Wait for response to get high part of serial
    // Profit????

    // Frame Header
    _xbeespi.write(0x7E);
    // Frame Length
    _xbeespi.write(0x00);
    _xbeespi.write(0x04);

    // Frame type (config)
    _xbeespi.write(0x08);
    checksumsub += 0x08;
    _xbeespi.write(0x52);
    checksumsub += 0x52;

    // Setting wanted SerialHigh
    _xbeespi.write(0x53);
    checksumsub += 0x53;
    _xbeespi.write(0x48);
    checksumsub += 0x48;

    // Calculate checksum
    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;
    // finally write checksum
    _xbeespi.write(checksum);

    // RECIEVE PORTION
    // Block until xbee replys
    while (_pin_attn != 0) { }

    // reset checksum to zero.
    checksum = 0;
    checksumsub = 0;

    // get start byte
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x7E) {
        // drop packet
        return 1;
    }
    // Get length of message (we don't care we know how long)
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);

    // Next read frame type to ensure it is an response packet.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x88) {
        // drop packet
        return 1;
    }
    checksumsub += temp1;

    // get response frame id
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x52) {
        // drop packet
        return 1;
    }
    checksumsub += temp1;

    // get at response parameter
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;

    if ((temp1 != 0x53) || (temp2 != 0x48)) {
        return 1;
        // drop
    }

    // Check OK flag
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x00) {
        return 1;
        // drop
    }
    checksumsub += temp1;

    // Now for the high portion of the serial
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;
    temp3 = _xbeespi.write(0x00);
    checksumsub += temp3;
    temp4 = _xbeespi.write(0x00);
    checksumsub += temp4;

    // Store new items in serial number
    serialNumber += (temp1 << 56) ^ (temp2 << 48) ^ (temp3 << 40) ^ (temp4 << 32);

    // Get that salty checksum
    temp1 = _xbeespi.write(0x00);

    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // Check the checksum
    if (temp1 != checksum) {
        // Checksum failure, flag to discard packet
        return 1;
    }

    ///////////////////////////////////////////////////Send portion
    // checksum Variables
    checksum = 0;
    checksumsub = 0;

    // Containers for read values
    temp1 = 0;
    temp2 = 0;
    temp3 = 0;
    temp4 = 0;

    // Write frame to return serial low.
    // Total frame looks like this:
    // 7E 00 04 08 52 53(S) 4C(L) CHECKSUM
    // Wait for response to get lower part of serial
    // Profit????

    // Frame Header
    _xbeespi.write(0x7E);
    // Frame Length
    _xbeespi.write(0x00);
    _xbeespi.write(0x04);

    // Frame type (config)
    _xbeespi.write(0x08);
    checksumsub += 0x08;
    _xbeespi.write(0x52);
    checksumsub += 0x52;

    // Setting wanted SerialLow
    _xbeespi.write(0x53);
    checksumsub += 0x53;
    _xbeespi.write(0x4C);
    checksumsub += 0x4C;

    // Calculate checksum
    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;
    // finally write checksum
    _xbeespi.write(checksum);

    // RECIEVE PORTION
    // Block until xbee replys
    while (_pin_attn != 0) { }

    // reset checksum to zero.
    checksum = 0;
    checksumsub = 0;

    // get start byte
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x7E) {
        // drop packet
        return 1;
    }
    // Get length of message (dont care again)
    _xbeespi.write(0x00);
    _xbeespi.write(0x00);

    // Next read frame type to ensure it is an response packet.
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x88) {
        // drop packet
        return 1;
    }
    checksumsub += temp1;

    // get response frame id
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x52) {
        // drop packet
        return 1;
    }
    checksumsub += temp1;

    // get at response parameter
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;

    if ((temp1 != 0x53) || (temp2 != 0x4C)) {
        return 1;
        // drop
    }

    // Check OK flag
    temp1 = _xbeespi.write(0x00);
    if (temp1 != 0x00) {
        return 1;
        // drop
    }
    checksumsub += temp1;

    // Now for the high portion of the serial
    temp1 = _xbeespi.write(0x00);
    checksumsub += temp1;
    temp2 = _xbeespi.write(0x00);
    checksumsub += temp2;
    temp3 = _xbeespi.write(0x00);
    checksumsub += temp3;
    temp4 = _xbeespi.write(0x00);
    checksumsub += temp4;

    serialNumber += (temp1 << 24) ^ (temp2 << 16) ^ (temp3 << 8) ^ (temp4);

    // Get that salty checksum
    temp1 = _xbeespi.write(0x00);

    checksumsub = checksumsub & 0xFF;
    checksum = 0xFF - checksumsub;

    // Check the checksum
    if (temp1 != checksum) {
        // Checksum failure, flag to discard packet
        return 1;
    }

    return serialNumber;
}

void xbee900hp::clearBuff() {
    while(_pin_attn == 0) {
        _xbeespi.write(0x00);
    }
}

char xbee900hp::xbee_getc() {
    return _xbeespi.write(0x00);
}