the firmware for xadow smartstrap for pebble

Dependencies:   BufferedSerial USBDevice XadowGPS XadowNFC mbed mbedPebbleSerial IAP

main.cpp

Committer:
KillingJacky
Date:
2015-11-06
Revision:
3:40e13433d193
Parent:
2:281fa9ce92c0

File content as of revision 3:40e13433d193:

#include "mbed.h"
#include "USBSerial.h"
#include "BufferedSerial.h"
#include "XadowGPS.h"
#include "XadowNFC.h"
#include "mbedPebbleSerial.h"
#include "IAP.h"

#define     EEP_BLOCK_SIZE        256
 
#define     TARGET_SECTOR    7      //  use sector  7 as target sector if it is on LPC11U24
#define     TARGET_EEPROM_ADDRESS   64
#define     TARGET_EEPROM_ADDRESS   64

#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))

#define SERVICE_BAT             0x2003
#define ATTR_BAT_V              0x1001
#define ATTR_BAT_CHG            0x1002

#define SERVICE_GPS             0x2001    //SPEC
#define ATTR_GPS_LOCATION       0x0001    //SPEC
#define ATTR_GPS_SPEED          0x0003    //spec
#define ATTR_GPS_ALTITUDE       0x1001
#define ATTR_GPS_FIX_QUALITY    0x0102    //SPEC
#define ATTR_GPS_SATELLITES     0x0101    //spec

#define SERVICE_NFC             0x1E01   //NFC is not in spec now, we chose id from experimentation range
#define ATTR_NFC_GET_UID        0x1001
#define ATTR_NFC_READ_NDEF      0x1002
#define ATTR_NFC_WRITE_NDEF     0x1003
#define ATTR_NFC_ERASE_NDEF     0x1004

uint8_t nfc_online, gps_online;
bool need_notify = false;

char    eep_block[ EEP_BLOCK_SIZE ];

static uint16_t SUPPORTED_SERVICES[20] = {0};
#define BUFFER_SIZE    200
static uint8_t s_pebble_buffer[GET_PAYLOAD_BUFFER_SIZE(BUFFER_SIZE)];

DigitalOut pin_chg_led_on(P0_2);
DigitalOut pin_5v_en(P1_19);
AnalogIn   ain(P0_11);

USBSerial dbg_serial;
BufferedSerial serial(P0_19, P0_18);  //(tx,rx)

I2C i2c(P0_5, P0_4);

Timer timer_notify;
Timer timer_service;

IAP   iap;

static uint8_t last_tagid[10] = {0};
static uint8_t last_tagid_len = 0;


float get_vbat()
{
    return 3.3f*ain*2.25;
}

void add_services()
{
    int i = 0;
    
    /* Raw data service */
    SUPPORTED_SERVICES[i++] = 0x0000;
    
    /* battery service */
    SUPPORTED_SERVICES[i++] = SERVICE_BAT;
    
    /* GPS service */
    if (gps_online)
    {
        SUPPORTED_SERVICES[i++] = SERVICE_GPS;
    }
    
    /* NFC Service*/
    if (nfc_online)
    {
        SUPPORTED_SERVICES[i++] = SERVICE_NFC;
        nfc_adapter_init();
    }
    
    mbedPebbleSerial::begin(s_pebble_buffer, sizeof(s_pebble_buffer), Baud9600, SUPPORTED_SERVICES, i);
}

int main()
{
    /* init io */
    pin_chg_led_on = 0; //pull low to enable charge led
    //pin_5v_en      = 1; //pull high to enable battery to charge pebble

    /* init uart */
    serial.baud(9600);

    wait(1);
    dbg_serial.printf("Detecting connected device...\r\n");

    /* GPS service */
    gps_online = gps_check_online();
    dbg_serial.printf("gps online: %d\r\n", gps_online);
    
    /* NFC Service*/
    nfc_online = nfc_check_online();
    dbg_serial.printf("nfc online: %d\r\n", nfc_online);

    dbg_serial.printf("Service self detecting done!\r\n");
    
    add_services();
    

    /* init i2c */
    i2c.frequency(100000); //100khz
    
    /* start a timer_notify */
    timer_notify.start();
    timer_service.start();
    
    /* reload the last configure for charging pebble or not */
    int r;
    r = iap.blank_check( TARGET_SECTOR, TARGET_SECTOR );
    dbg_serial.printf( "blank check result = 0x%08X\r\n", r );
    
    iap.prepare( TARGET_SECTOR, TARGET_SECTOR );
    
    if ( r == SECTOR_NOT_BLANK ) {
        r = iap.read_eeprom( (char*)TARGET_EEPROM_ADDRESS, eep_block, EEP_BLOCK_SIZE );
        dbg_serial.printf( "read eep result = 0x%08X, var: %d\r\n", r, eep_block[0] );
        
        pin_5v_en = eep_block[0] > 0?1:0;
    }else
    {
        eep_block[0] = 1;
        pin_5v_en = 1;
        r = iap.write_eeprom( eep_block, (char*)TARGET_EEPROM_ADDRESS, EEP_BLOCK_SIZE );
        dbg_serial.printf( "write eep result = 0x%08X\r\n", r );
    }
    
    size_t length;
    uint16_t service_id;
    uint16_t attribute_id;
    RequestType type;
        
    while(1) {
        if(mbedPebbleSerial::feed(&service_id, &attribute_id, &length, &type))
        {
            // we have a raw data frame to process
            if ((service_id == 0) && (attribute_id == 0)) 
            {
                ;
            }
            else if (service_id == SERVICE_BAT)
            {
                if ((attribute_id == ATTR_BAT_V) && (type == RequestTypeRead)) 
                {
                    float vbat_f = get_vbat();
                    uint16_t vbat = (uint16_t)(vbat_f * 100);
                    dbg_serial.printf("ATTR_BAT_V, vbat: %f, %d\r\n", vbat_f, vbat);
                    memcpy(s_pebble_buffer, &vbat, sizeof(vbat));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(vbat));
                }
                else if((attribute_id == ATTR_BAT_CHG) && (type == RequestTypeWrite))
                {
                    uint8_t enable_charge;
                    memcpy(&enable_charge, s_pebble_buffer, sizeof(enable_charge));
                    dbg_serial.printf("ATTR_BAT_CHG: %d\r\n", enable_charge);
                    pin_5v_en = enable_charge;
                    mbedPebbleSerial::write(true, NULL, 0);
                    eep_block[0] = enable_charge;
                    r = iap.write_eeprom( eep_block, (char*)TARGET_EEPROM_ADDRESS, EEP_BLOCK_SIZE );
                    dbg_serial.printf( "write %d to eep result = 0x%08X\r\n", enable_charge, r );
                }  
                else
                {
                    mbedPebbleSerial::write(false, NULL, 0);
                }                
            }
            else if (service_id == SERVICE_GPS && gps_online)
            {
                if (attribute_id == ATTR_GPS_LOCATION && type == RequestTypeRead)
                {
                    float lat_f, lon_f;
                    lat_f = gps_get_latitude();
                    lon_f = gps_get_longitude();
                    int32_t lat = (int32_t)(lat_f * (10000000));
                    int32_t lon = (int32_t)(lon_f * (10000000));
                    dbg_serial.printf("ATTR_GPS_LOCATION: %f, %f ---- %d, %d\r\n", lat_f,lon_f,lat,lon);
                    memcpy(s_pebble_buffer, &lat, sizeof(lat));
                    memcpy(s_pebble_buffer+sizeof(lat), &lon, sizeof(lon));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(lat)*2);
                }
                else if (attribute_id == ATTR_GPS_SPEED && type == RequestTypeRead)
                {
                    float v = gps_get_speed();
                    uint16_t speed = (uint16_t)(v * 100);
                    dbg_serial.printf("ATTR_GPS_SPEED: %f, %d\r\n", v,speed);
                    memcpy(s_pebble_buffer, &speed, sizeof(speed));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(speed));
                }
                else if (attribute_id == ATTR_GPS_ALTITUDE && type == RequestTypeRead)
                {
                    float alt_f = gps_get_altitude();
                    uint16_t alt = (uint16_t)(alt_f * 100);
                    dbg_serial.printf("ATTR_GPS_ALTITUDE: %f, %d\r\n", alt_f,alt);
                    memcpy(s_pebble_buffer, &alt, sizeof(alt));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(alt));
                }
                else if (attribute_id == ATTR_GPS_FIX_QUALITY && type == RequestTypeRead)
                {
                    uint8_t fixq = gps_get_position_fix();
                    fixq = (fixq>8)?0:fixq;
                    dbg_serial.printf("ATTR_GPS_FIX_QUALITY: %d\r\n", fixq);
                    memcpy(s_pebble_buffer, &fixq, sizeof(fixq));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(fixq));
                }
                else if (attribute_id == ATTR_GPS_SATELLITES && type == RequestTypeRead)
                {
                    uint8_t sat = gps_get_sate_in_veiw();
                    dbg_serial.printf("ATTR_GPS_SATELLITES: %d\r\n", sat);
                    memcpy(s_pebble_buffer, &sat, sizeof(sat));
                    mbedPebbleSerial::write(true, s_pebble_buffer, sizeof(sat));
                }else
                {
                    mbedPebbleSerial::write(false, NULL, 0);
                }
            }
            else if (service_id == SERVICE_NFC && nfc_online)
            {
                if (attribute_id == ATTR_NFC_GET_UID && type == RequestTypeRead)
                {
                    /*uint8_t *uid = nfc_adapter_get_uid();
                    uint8_t len = uid[1];
                    dbg_serial.printf("GET_NFC_TAGID: ");
                    for(int i=2; i<2+len; i++)
                    {
                        dbg_serial.printf("%02X ", uid[i]);
                    }
                    dbg_serial.printf("\r\n");
                    memcpy((char *)s_pebble_buffer, (char *)(uid+2), len);
                    mbedPebbleSerial::write(true, s_pebble_buffer, len);*/
                    dbg_serial.printf("GET_NFC_TAGID: ");
                    for(int i=0; i<last_tagid_len; i++)
                    {
                        dbg_serial.printf("%02X ", last_tagid[i]);
                    }
                    dbg_serial.printf("\r\n");
                    memcpy((char *)s_pebble_buffer, (char *)last_tagid, last_tagid_len);
                    mbedPebbleSerial::write(true, s_pebble_buffer, last_tagid_len);
                    
                    need_notify = false;
                }
                else if (attribute_id == ATTR_NFC_READ_NDEF && type == RequestTypeRead)
                {
                    memset(s_pebble_buffer, 0, sizeof(s_pebble_buffer));
                    uint8_t *ndef = nfc_adapter_read();
                    uint8_t len = ndef[1];
                    len = min(len, BUFFER_SIZE);
                    dbg_serial.printf("GET_NFC_NDEF: ");
                    for(int i=2; i<2+len; i++)
                    {
                        dbg_serial.printf("%02X ", ndef[i]);
                    }
                    dbg_serial.printf("\r\n");
                    memcpy((char *)s_pebble_buffer, (char *)(ndef+2), len);
                    mbedPebbleSerial::write(true, s_pebble_buffer, len);
                }
                else if((attribute_id == ATTR_NFC_WRITE_NDEF) && (type == RequestTypeWrite))
                {
                    if (*(s_pebble_buffer + length) != '\0' && length < BUFFER_SIZE)
                        *(s_pebble_buffer + length) = '\0';
                    dbg_serial.printf("ATTR_NFC_WRITE_NDEF: ");
                    for(int i=0; i<length; i++)
                    {
                        dbg_serial.printf("%02X ", s_pebble_buffer[i]);
                    }
                    dbg_serial.printf("\r\n");
                    nfc_adapter_write(s_pebble_buffer, length);
                    mbedPebbleSerial::write(true, NULL, 0);
                }  
                else if((attribute_id == ATTR_NFC_ERASE_NDEF) && (type == RequestTypeWrite))
                {
                    dbg_serial.printf("ATTR_NFC_ERASE_NDEF\r\n");
                    nfc_adapter_erase();
                    mbedPebbleSerial::write(true, NULL, 0);
                } else
                {
                    mbedPebbleSerial::write(false, NULL, 0);
                } 
            }else
            {
                mbedPebbleSerial::write(false, NULL, 0);
            }
        }
        
        //check if nfc tagid changed
        if (timer_notify.read_ms() > 1000 && nfc_online)
        {
            timer_notify.reset();
            
            if (need_notify)
            {
                mbedPebbleSerial::notify(SERVICE_NFC, ATTR_NFC_GET_UID);
            }else
            {
                uint8_t *uid = nfc_adapter_get_uid();
                uint8_t len = uid[1];
                dbg_serial.printf("Check NFC: ");
                if (len > 0)
                {
                   for(int i=2; i<2+len; i++)
                    {
                        dbg_serial.printf("%02X ", uid[i]);
                    }
                }
                dbg_serial.printf("\r\n");
                len = min(len, 10);
                if (memcmp(last_tagid, uid+2, len) != 0 || len != last_tagid_len)
                {
                    need_notify = true;
                    mbedPebbleSerial::notify(SERVICE_NFC, ATTR_NFC_GET_UID);
                    if (len == 0)
                    {
                        memset(last_tagid, 0, sizeof(last_tagid));
                    }else
                    {
                        memcpy(last_tagid, uid+2, len);
                    }
                    last_tagid_len = len;
                    //changed, notify
                }
            }
        }
        
        
        
        //check services' availability
        if (timer_service.read() > 5)
        {
            timer_service.reset();
            
            uint8_t state_gps = gps_check_online();
            uint8_t state_nfc = nfc_check_online();
            uint8_t mark = 0;
            
            if (state_gps != gps_online)
            {
                gps_online = state_gps;
                mark = 1;
                dbg_serial.printf("gps state: %d \r\n", gps_online);
            }
            if (state_nfc != nfc_online)
            {
                nfc_online = state_nfc;
                mark = 1;
                dbg_serial.printf("nfc state: %d \r\n", nfc_online);
            }
            if (mark)
            {
                add_services();
            }
            
            dbg_serial.printf("check services --- %d, %d \r\n", gps_online, nfc_online);
        }
        
    }  //while 1
}