Cast tube base station

Dependencies:   EALib USBDevice mbed

main.cpp

Committer:
BPPearson
Date:
2016-01-05
Revision:
1:240b94a8d002
Parent:
0:e559b5160d84

File content as of revision 1:240b94a8d002:

/******************************************************************************
 * Includes
 *****************************************************************************/
#include "mbed.h"
#include "XBee.h"
#include "USBHID.h"
#include "ByteOperations.h"
#include "USBHIDProtocol.h"

/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/

// define NODE_IS_COORDINATOR if this board should act
// as XBee coordinator. Make sure it is undefined if the board
// should act as End-Device
//#define NODE_IS_COORDINATOR (0)

//#define CMD_BTN_MSG (0)
//#define CMD_ACK_MSG (1)
//#define NUMBER_OF_ZONES 72
//#define ECHO_SERVER_PORT   7
#define VERSION 0x01
#define COMMAND 0
#define DATA 1

#define XBeeDisconnected       0x400
#define MaxTeethExceeded       0x800

// rotational stage modes
#define STOPPED             1
#define PARKING             2
#define GOTOMDPOSITION      3
#define DRIVINGTOPOSITION   4
#define STARTROTATING       5
#define ROTATING            6
#define MDSCAN              7

#define MAX_TEETH           384

#define LOW                 0
#define HIGH                1


// input/output devices
static XBee xbee(P4_22, P4_23, P4_17, P4_19);
static DigitalIn indexInputLevel(p10);
static DigitalIn zeroInputLevel(p11);
static DigitalOut led1(LED1);        // led1 + led 2 -> active low
static DigitalOut led2(LED2);
static DigitalOut led3(LED3);             // led3 + led 4 -> active high
static DigitalOut led4(LED4);
static DigitalOut motorDrive(p12);
Serial pc(USBTX, USBRX); // tx, rx
Ticker lossOfSignalTimer;
Ticker updateLCD;
Ticker rotationalControl;
Ticker debounceDigInputs;
Ticker ledPulseCheck;
BusInOut databus(p25, p26, p27, p28, p29, p30, p31, p32);
DigitalOut registerSelect(p39);
DigitalOut readWrite(p38);
DigitalOut readWriteClock(p37);

USBHID *hid;
HID_REPORT send_report __attribute__((aligned (4))); // Aligned for fast access
HID_REPORT recv_report __attribute__((aligned (4))); // Aligned for fast access



// local variables
float rawTemperature = 0.0;
float rawThickness = 0.0;
uint32_t position = 0;
uint32_t seqNo = 0;
uint32_t prevSeqNo = 0;
bool xbeeIsUp = false;
bool saveProfileToDatabase = false;
char inBuff[256];
char outBuff[256];
uint8_t xbeeSigStrength = 0;
uint32_t errorFlags = 0;
int rotationalMode = STOPPED;
int mdPosition = 0;
int toothLowCount = 0;
int zeroLowCount = 0;
int zeroHighCount = 0;
int led1Duration = 0;
int led2Duration = 0;
int led3Duration = 0;
int led4Duration = 0;
int parkPosition = 0;
int indexInputState = HIGH;
int zeroInputState = HIGH;


void pulseLed(int led, int duration)
{
    
    switch (led)
    {
        case LED1:
            led1 = 0;            // turn on led
            led1Duration = duration;            // set duration
            break;
        case LED2:
            led2 = 0;            // turn on led
            led2Duration = duration;            // set duration
            break;
        case LED3:
            led3 = 1;            // turn on led
            led3Duration = duration;            // set duration
            break;
        case LED4:
            led4 = 1;            // turn on led
            led4Duration = duration;            // set duration
            break;
        default: ;
    }
}



void ledPulser()
{

    if (led1Duration > 0)
    {
        led1Duration--;
        
        if (led1Duration == 0)
            led1 = 1;            // turn led off
    }

    if (led2Duration > 0)
    {
        led2Duration--;
        
        if (led2Duration == 0)
            led2 = 1;           // turn led off
    }

    if (led3Duration > 0)
    {
        led3Duration--;
        
        if (led3Duration == 0)
            led3 = 0;            // turn led off
    }

    if (led4Duration > 0)
    {
        led4Duration--;
        
        if (led4Duration == 0)
            led4 = 0;            // turn led off
    }
}


 
 
 
 
void debounceInputs()
{
    

    if (indexInputLevel == 0)
    {
        if (toothLowCount < 5)              // times 10 mS for debounce period
        {
            toothLowCount++;
            
            if (toothLowCount >= 5)
            {
                position++;
                    
                if (position >= MAX_TEETH)
                {
                    position = 0;
                    errorFlags |= MaxTeethExceeded;
                }
            }
        }
    }
    else
        toothLowCount = 0;

    if (zeroInputLevel == 0)
    {
        if (zeroLowCount < 5)             // times 10 mS debounce period
        {
            zeroLowCount++;
            
            if (zeroLowCount >= 5)
            {
                position = 0;                // zero position counter
            }
        }
    }
    else
    {
        zeroLowCount = 0;
    }
}




static void xbeeDeviceUp(void) 
{
    xbeeIsUp = true;
}



static void xbeeDeviceDown(void) 
{
    xbeeIsUp = false;
}



static void xbeeNodeFound(void) 
{
    uint32_t addrHi = 0;
    uint32_t addrLo = 0;
    uint8_t rssi = 0;

    xbee.getRemoteAddress(&addrHi, &addrLo);
    xbee.getRssi(&rssi);
}


static void xbeeTxStat(void) 
{

    uint8_t frameId = 0;
    XBee::XBeeTxStatus status = XBee::TxStatusOk;

    xbee.getTxStatus(&frameId, &status);
}



static void xbeeDataAvailable(void) 
{
    char* data = NULL;
    uint8_t len = 0;
    uint32_t addrHi = 0;
    uint32_t addrLo = 0;

    xbee.getRemoteAddress(&addrHi, &addrLo);
    xbee.getData(&data, &len);
    //xbee.getRssi(&rssi);

    if (len > 0) {

        switch(data[0]) 
        {
            case '1':
                if (len > 1) 
                {
                    pulseLed( LED4, 5);
                    
                    // get values from data packet 
                    // packet format - sprintf(data, "1%5.3f, %5.3f, %5.3f, %5.3f, %4x\n", rawTemperature, rawThickness, filteredTemperature, filteredThickness, errorFlags);
                    sscanf(&data[1], "%f,%f, %x\n", &rawTemperature, &rawThickness, &errorFlags);
                }
                break;
                
            default:
                pc.printf("Unknown packet format %d\n", data[0]);
        }
    }
}



static bool xbeeInit()
{
    xbee.registerCallback(xbeeDeviceUp, XBee::CbDeviceUp);

    xbee.registerCallback(xbeeDeviceDown, XBee::CbDeviceDown);

    xbee.registerCallback(xbeeNodeFound, XBee::CbNodeFound);

    xbee.registerCallback(xbeeTxStat, XBee::CbTxStat);

    xbee.registerCallback(xbeeDataAvailable, XBee::CbDataAvailable);

    XBee::XBeeError err = xbee.init(XBee::EndDevice, "EAEA");

    if (err != XBee::Ok) 
    {
        return false;
    }

    return true;
}


static void reportInitFailed() 
{
    while (true) {
        wait_ms(200);
    }
}


static void ledInit() 
{
    led1 = 1;         // turn off
    led2 = 1;         // turn off
    led3 = 0;         // turn off
    led4 = 0;         // turn off
}


void empty_report(HID_REPORT *data){
    register uint32_t *p = (uint32_t *)data->data;
    for( register int i=0; i<((sizeof(HID_REPORT)-1)/4); i++ ){
        *p = 0xFFFFFFFF;
        p++;
    }
}



void processUSB()
{
    uint8_t hiPosition;
    uint8_t loPosition;
    
    if(hid->readNB(&recv_report))    //try to read a msg
    {
        pulseLed(LED3, 5);        // pulse led3 to show USB activity
        
        // Data packet received, start parsing
        int irx=0;
        int itx=0;

        send_report.data[itx++] = recv_report.data[0];

        switch ( recv_report.data[irx++] )
        {
            case CMD_SYS_CHECK:
                send_report.data[itx++] =  VERSION;
                break;
                
            case CMD_SYS_RESET: 
                empty_report(&recv_report);                // Soft reset
                break;
                
            case CMD_CURRENT_VALUES:
                write_32_to_8(&itx, send_report.data, (uint32_t)(rawTemperature * 1000));
                write_32_to_8(&itx, send_report.data, (uint32_t)(rawThickness * 1000));
                write_32_to_8(&itx, send_report.data, position);
                write_32_to_8(&itx, send_report.data, xbeeSigStrength);
                write_32_to_8(&itx, send_report.data, errorFlags);
                write_32_to_8(&itx, send_report.data, rotationalMode);
                break;

            case PARK_AT_ZERO:
                parkPosition = MAX_TEETH - 2;       // to allow it to slow donw and hit zero
                rotationalMode = PARKING;
                break;

            case PARK_AT_POSITION:
                hiPosition = recv_report.data[irx++];
                loPosition = recv_report.data[irx++];
                parkPosition = (hiPosition << 8) + loPosition;

                parkPosition -= 2;       // to allow it to slow down and hit the required position
                if (parkPosition < 0)
                    parkPosition += MAX_TEETH;
                rotationalMode = PARKING;
                break;

            case MD_SCAN:
                hiPosition = recv_report.data[irx++];
                loPosition = recv_report.data[irx++];
                mdPosition = (hiPosition << 8) + loPosition;
                rotationalMode = GOTOMDPOSITION;
                break;

            case ROTATIONAL_SCAN:
                rotationalMode = STARTROTATING;
                break;

            case 0xEE: 
                hid->sendNB(&send_report);  
                break;

            default:
                send_report.data[0] =   0xFF;   //Failure
                break;
        }

        hid->send(&send_report);        // Return command + optional new args

        empty_report(&recv_report);         
        empty_report(&send_report);
    }
}

        
void checkForLossOfSignal()
{

        xbee.getRssi(&xbeeSigStrength);
}



void writeToLCD(bool rs, char data)
{

    registerSelect = rs;    // set register select pin 
    
    readWrite = 0;    // set read/write pin to write
    
    databus.output();    // set bus as output
    
    databus = data;    // put data onto bus
    
    readWriteClock = 1;    // pulse read/write clock
    
    wait_us(1);
    
    readWriteClock = 0;

    wait_us(1);
    
    databus = 0;    // clear data bus
}



char readFromLCD(bool rs)
{

    char data;
    
    registerSelect = rs;    // set register select pin 
    
    readWrite = 1;    // set read/write pin to read
    
    databus.input();    // set bus as input
    
    data = databus;    // read data from bus
    
    readWriteClock = 1;    // pulse read/write clock
    
    wait_us(10);
    
    readWriteClock = 0;
    
    return data;
}


void resetLCD()
{
}


void initLCD(){
    
    readWrite = 0;    // set output so we always write to LCD
    
    wait_ms(15);    // wait 15 ms to allow LCD to initialise
    
    writeToLCD(COMMAND, 0x30);    // set interface for 8 bit mode

    wait_ms(5);    // give it time    

    writeToLCD(COMMAND, 0x30);    // set interface for 8 bit mode again

    wait_us(100);    // give it time    

    writeToLCD(COMMAND, 0x30);    // set interface for 8 bit mode again, last one before we can configure the display

    wait_us(500);    // give it time    
    
    writeToLCD(COMMAND, 0x38);    // set interface for 8 bit mode, 2 display lines and 5 x 8 character font

    wait_us(100);    // give it time    
    
    writeToLCD(COMMAND, 0x08);    // display off

    wait_us(100);    // give it time    
    
    writeToLCD(COMMAND, 0x01);    // clear the screen

    wait_ms(2);    // give it time to finish    

    writeToLCD(COMMAND, 0x03);    // set entry mode to increment cursor position cursor on write
    
    wait_us(100);    // give it time to finish    

    writeToLCD(COMMAND, 0x02);    // position cursor at home
    
    wait_ms(2);    // give it time to finish    

    writeToLCD(COMMAND, 0x0C);    // display on
}




void positionCursor(uint8_t x, uint8_t y)
{

    switch (y)
    {
        case 0:
            writeToLCD(COMMAND, 0x80 + 0x00 + x);
            break;

        case 1:
            writeToLCD(COMMAND, 0x80 + 0x40 + x);
            break;

        case 2:
            writeToLCD(COMMAND, 0x80 + 0x14 + x);
            break;

        case 3:
            writeToLCD(COMMAND, 0x80 + 0x54 + x);
            break;

        default: 
            writeToLCD(COMMAND, 0x80 + 0x00 + x);
    }       

    wait_us(50);
}



void clearLcdScreen()
{

    writeToLCD(COMMAND, 0x01);
        
    wait_ms(2);
}



void displayString(int x, int y, char *str)
{
    
    positionCursor(x, y);        // position cursor
    
    for (int i=0; i<strlen(str); i++)    // write string to screen
    {
        writeToLCD(DATA, str[i]);
        
        wait_us(50);
    }
}


 
 void updateDisplay()
 {
    char lineStr[20];
  
    clearLcdScreen();
    
    sprintf( lineStr, "Thickness %4.2f mm", rawThickness);

    displayString(0, 0, lineStr);

    sprintf( lineStr, "Temperature %4.1f C ", rawTemperature);

    displayString(0, 1, lineStr);

    sprintf( lineStr, "Sig strength %2d", xbeeSigStrength);

    displayString(0, 2, lineStr);

    switch (rotationalMode)
    {
        case STOPPED:
            displayString(0, 3, "Parked");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case PARKING:
            displayString(0, 3, "Parking");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case GOTOMDPOSITION:
            displayString(0, 3, "Go to MD pos");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case DRIVINGTOPOSITION:
            displayString(0, 3, "Go to MD pos");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case STARTROTATING:
            displayString(0, 3, "Start scan");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case ROTATING:
            displayString(0, 3, "Scanning");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        case MDSCAN:
            displayString(0, 3, "MD scanning");
            sprintf( lineStr, "%3d", position);
            displayString(16, 3, lineStr);
            break;

        default: 
            break;
    }

}
 

 void displayDebugMsg(char *str)
 {
    
    clearLcdScreen();
    
    displayString(0, 0, str);
}
 


void checkRotationMode()
{
    
    switch (rotationalMode)
    {
        case STOPPED:
            break;

        case PARKING:
            if (motorDrive == 0)
                motorDrive = 1;
                
            if (position == parkPosition)
            {
                motorDrive = 0;
                rotationalMode = STOPPED;
            }
            break;

        case GOTOMDPOSITION:
            motorDrive = 1;
            rotationalMode = DRIVINGTOPOSITION;
            break;

        case DRIVINGTOPOSITION:
            if (position == mdPosition)
            {
                motorDrive = 0;
                rotationalMode = MDSCAN;
            }
            break;

        case STARTROTATING:
                motorDrive = 1;
                rotationalMode = ROTATING;
            break;

        case ROTATING:
            break;

        default: 
            break;
    }
}




int main() 
{

    ledInit();    // initialise leds
 
    motorDrive = 0;    // set motor drive output to off   

    initLCD();    // initialize the LCD
    
    displayDebugMsg("Initializing XBee");

    if (!xbeeInit()) {
        reportInitFailed();
    }

    // Wait until XBee node is reported to be up.
    // - For End-device this means that the node is associated with a
    //   coordinator
    // - For a coordinator this means that the node is initialized and ready
    displayDebugMsg("Connecting to XBee");

    while(!xbeeIsUp) 
    {
        xbee.process();
    }

    displayDebugMsg("        ");    // clear display

    displayDebugMsg("Initialising USB");

    static USBHID hid_object(64, 64);    // USB Initialize   

    displayDebugMsg("USB initialised");

    hid = &hid_object;
    send_report.length = 64;

    displayDebugMsg("Starting tickers");

    lossOfSignalTimer.attach(&checkForLossOfSignal, 2.0);   // check for loss of signal every 2 seconds

    updateLCD.attach(&updateDisplay, 1.0);
    
    rotationalControl.attach(checkRotationMode, 0.05);

    debounceDigInputs.attach(debounceInputs, 0.01);
    
    ledPulseCheck.attach(ledPulser, 0.01);

    ledInit();    // turn off all leds as initialisation complete

    displayDebugMsg("while (1)");

    while (1) 
    {
        if (xbeeIsUp) 
        {
            xbee.process();
            
            processUSB();
    
            wait_ms(2);
        }
        else
        {
            errorFlags = XBeeDisconnected;            // set error flag for no connection to XBee

            rawTemperature = 0.0;            // clear display values
            rawThickness = 0.0;
        }
    }
}