test publish

Dependencies:   BLE_API nRF51822 mbed

Fork of KS7 by masaaki makabe

main.cpp

Committer:
masaaki_makabe
Date:
2016-08-12
Branch:
KS3
Revision:
36:3cca74c30551
Parent:
33:d7b53d548c33

File content as of revision 36:3cca74c30551:

#include "mbed.h"
#include "exio.h"
#include "BLE.h"
#include "DFUService.h"
#include "common.h"
#include <stdlib.h>
#include <arm_math.h>
#include "CurrentTimeService.h"
#include "MMA845x.h"
#include "common.h"


// BLE
#define INTERVAL_500MSEC        (500UL)
#define CONNTIMEOUT_3000MSEC    (3000UL)
#define ADV_TIMEOUT             (0)
#define DEVICE_NAME "Kitchen Scale"
#define BLE_TXPOWER_4DBM        (4)

// Device Information Service (DIS) (20 character limit)
// https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml
#define MANUFACTURER_NAME_STRING        "Hacarus" // Manufacturer Name String - shall represent the name of the manufacturer of the device.
#define MODEL_NUMBER_STRING             "0001" // Model Number String - shall represent the model number that is assigned by the device vendor.
#define SERIAL_NUMBER_STRING            "000780c0ffeef00d"  // Serial Number String - shall represent the serial number for a particular instance of the device.
#define FIRMWARE_REVISION_STRING        "v1.00.009@rev0028" // Firmware Revision String - shall represent the firmware revision for the firmware within the device.

// Weight Scale Service (Original)
//#define UUID_WEIGHT_SCALE_SERVICE       (0x181D)

#if defined(PCB_VER1) || defined(PCB_VER2)
// Switch
#define SW_THRESHOLD            (0.5)
#define SW_SAMPLECOUNT          (3)
#endif

// Mode
#define MODE_OFF    (0) // LED OFF
#define MODE_START  (1) // LED OFF -> ON
#define MODE_ON     (2) // LED ON
#define MODE_END    (3) // LED ON -> OFF
/*S-----------------------------------------------------------*/
State_t _state = S_WATCH;
Mode_t _mode = M_SCALE;
/*E-----------------------------------------------------------*/

// Led
#define LED_INTERVAL_MSEC   (100)
#define BRIGHTNESS_ADDVALUE (0.1)
#define BRIGHTNESS_MINVALUE (0.0)
#define BRIGHTNESS_MAXVALUE (1.0)

// Properties
//io io;
/*S---------------------------------------------------------------*/
//io io(P0_15, P0_13); // HX711's CLK & DAT
exio io;
DFUService *p_dfu;
/*E---------------------------------------------------------------*/
//io(P0_5, P0_4); // HX711's CLK & DAT for BLEnano debug
uint32_t weight_data;
float32_t weight = 0.0;
uint32_t scale = 0;
int update_counter = 0;
#if defined(PCB_VER1) || defined(PCB_VER2)
float sw_data[SW_SAMPLECOUNT];
uint8_t sw_count = 0;
#endif
int led_mode = MODE_OFF;
float led_brightness = BRIGHTNESS_MINVALUE;

#ifdef UART_DEBUG
#if defined(PCB_VER1) || defined(PCB_VER2)
Serial pc(P0_9, P0_8);// TX=P0_9
#else
Serial pc(P0_9, P0_11);// TX=P0_9
#endif
#define UART_BAUD_RATE   (9600UL)
#define DEBUG(...)              { pc.printf(__VA_ARGS__); }
#else
#define DEBUG(...) {}
#endif

Timer t;

// BLE
BLE ble;
Gap::ConnectionParams_t connectionParams;

/* Complete list of 16-bit Service IDs */
uint16_t    uuid16_list[] = {GattService::UUID_DEVICE_INFORMATION_SERVICE};

/* Weight Scale Service */
static const uint8_t UUID_HACARUS_WEIGHT_CHAR[] = {0x00, 0x00, 0x2A, 0x9D, 0x00, 0x01, 0x00, 0x01, 0x00, 'H','a', 'c', 'a', 'r','u', 's'};
GattCharacteristic  WeightMeasurement (UUID(UUID_HACARUS_WEIGHT_CHAR), (uint8_t *)&weight_data, sizeof(weight_data), sizeof(weight_data),
                                       GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
static const uint8_t UUID_HACARUS_SCALE_CHAR[] = {0x00, 0x00, 0x2A, 0x9E, 0x00, 0x01, 0x00, 0x01, 0x00, 'H','a', 'c', 'a', 'r','u', 's'};
GattCharacteristic  WeightScale (UUID(UUID_HACARUS_SCALE_CHAR), (uint8_t *)&scale, sizeof(scale), sizeof(scale),
                                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
GattCharacteristic *Chars[] = {&WeightMeasurement,&WeightScale};
static const uint8_t UUID_HACARUS_WEIGHT_SERVICE[] = {0x00, 0x00, 0x18, 0x1D, 0x00, 0x01, 0x00, 0x01, 0x00, 'H','a', 'c', 'a', 'r','u', 's'};
GattService HWS = GattService(UUID(UUID_HACARUS_WEIGHT_SERVICE), Chars, sizeof(Chars) / sizeof(GattCharacteristic *));

/* Device Information Service */
GattCharacteristic ManuName(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR, (uint8_t *)&MANUFACTURER_NAME_STRING, sizeof(MANUFACTURER_NAME_STRING) - 1, sizeof(MANUFACTURER_NAME_STRING) - 1,
                            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic ModelNum(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR, (uint8_t *)&MODEL_NUMBER_STRING, sizeof(MODEL_NUMBER_STRING) - 1, sizeof(MODEL_NUMBER_STRING) - 1,
                            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic SerialNum(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR, (uint8_t *)&SERIAL_NUMBER_STRING, sizeof(SERIAL_NUMBER_STRING) - 1, sizeof(SERIAL_NUMBER_STRING) - 1,
                             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic FWVersion(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR, (uint8_t *)&FIRMWARE_REVISION_STRING, sizeof(FIRMWARE_REVISION_STRING) - 1, sizeof(FIRMWARE_REVISION_STRING) - 1,
                             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *DISChars[] = {&ManuName, &ModelNum, &SerialNum, &FWVersion};
GattService        DIS(GattService::UUID_DEVICE_INFORMATION_SERVICE , DISChars, sizeof(DISChars) / sizeof(GattCharacteristic *));

/*S--------------------------------------------------------------------*/
CurrentTimeService *p_CurrentTimeService; // Current Time Service
MMA845x *p_MMA845x; // 加速度センサー(本体)
I2C i2c(P0_17, P0_18); // 加速度センサー(I2C)
/*E--------------------------------------------------------------------*/

#ifdef PCB_VER1
bool check_joystick()
{
    float sum_data = 0;

    sw_data[sw_count] = io.get_x();

    if(++sw_count >= SW_SAMPLECOUNT) {
        sw_count = 0;
    }

    for(int count = 0; count < SW_SAMPLECOUNT; count++) {
        sum_data += sw_data[count];
    }

    return ((sum_data / SW_SAMPLECOUNT) >= SW_THRESHOLD);
}
#endif

uint32_t quick_ieee11073_from_float(float data)
{
    uint8_t  exponent = 0xFE; //exponent is -2
    uint32_t mantissa = (uint32_t)(data*100);

    return ( ((uint32_t)exponent) << 24) | mantissa;
}

#if defined(PCB_VER1) || defined(PCB_VER2)
void SWInit(void)
{
    // SW Initialize
    for(int count = 0; count < SW_SAMPLECOUNT; count++) {
        sw_data[count] = 0;
    }
}
#endif

void AppInit(void)
{

#if defined(PCB_VER1) || defined(PCB_VER2)
    SWInit();
#endif
    io.analog_pow(1);

#ifdef PCB_VER3
    // check XTALFREQ for TaiyoYuden module in PCB_VER3
    /*
            if(NRF_UICR->XTALFREQ == 0xFFFFFF00){
                io.display_value = 3232;
            }else if(NRF_UICR->XTALFREQ == 0xFFFFFFFF){
                io.display_value = 1616;
            }
    */
#endif
}

/*
 * BLE CallBacks
 */
void BLEConnectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    ble.updateConnectionParams(params->handle, params->connectionParams);
#ifdef UART_DEBUG
    pc.printf("BLEConnectionCallback \r\n");
#endif
}

void BLEDisconnectionCallback(const Gap::DisconnectionCallbackParams_t  *params)
{
    if(led_mode == MODE_ON) {
        ble.startAdvertising();
    }
#ifdef UART_DEBUG
    pc.printf("BLEDisconnectionCallback \r\n");
#endif
}

void BLERadioNotificationCallback(bool radio_active)
{
    if (radio_active == false) {
        if(led_mode == MODE_ON) {
        }
    }
#ifdef UART_DEBUG
    pc.printf("BLERadioNotificationCallback \r\n");
#endif
}



void BleInitialize(void)
{

    uint8_t advertiseServiceID[16];

    // Initialize
    ble.init();

    // Event Set
    ble.onConnection(&BLEConnectionCallback);
    ble.onDisconnection(&BLEDisconnectionCallback);
    ble.onRadioNotification(&BLERadioNotificationCallback);

    ble.getPreferredConnectionParams(&connectionParams);
    connectionParams.maxConnectionInterval = INTERVAL_500MSEC;
    connectionParams.minConnectionInterval = INTERVAL_500MSEC;
    connectionParams.connectionSupervisionTimeout = CONNTIMEOUT_3000MSEC;
    connectionParams.slaveLatency = 2;
    ble.setPreferredConnectionParams(&connectionParams);

    ble.setTxPower(BLE_TXPOWER_4DBM);

    for(int i=0; i<16; i++) {
        advertiseServiceID[i] = UUID_HACARUS_WEIGHT_SERVICE[16 - 1 - i];
    }

    ble.accumulateAdvertisingPayload((GapAdvertisingData::Flags)(GapAdvertisingData::LE_GENERAL_DISCOVERABLE | GapAdvertisingData::BREDR_NOT_SUPPORTED));
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME,
                                     (const uint8_t *)DEVICE_NAME,
                                     strlen(DEVICE_NAME));
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)advertiseServiceID, sizeof(advertiseServiceID));

    ble.setAdvertisingInterval(INTERVAL_500MSEC);
    ble.setAdvertisingTimeout(ADV_TIMEOUT); /* 0 is disable the advertising timeout. */

/*S-----------------------------------------------------------------------*/
    /*CurrentTimeServiceの初期化とサービス追加*/
    ble_date_time_t dt; // 1970/1/1 00:00:00 以降の初期値
    dt.year = 2016;
    dt.month = 7;
    dt.day = 31;
    dt.hours = 23;
    dt.minutes = 45;
    dt.seconds = 0;
    p_CurrentTimeService = new CurrentTimeService(ble, dt); 
/*E-----------------------------------------------------------------------*/        
    ble.addService(HWS);
    ble.addService(DIS);
// DFUサービスがスタックに割り当たっていたのをヒープへ移動
   //DFUService dfu(ble);
    p_dfu = new DFUService(ble);
}
/*S---------------------------------------------------------------------*/
/*キー押されて1sec経過すればコールバックされる*/
int _key1sec = 0;
bool _analog_skip = false;
void KeyOn(void)
{
    _key1sec = 1;
}
void AccelInit(void)
{
    /*加速度センサー初期化*/
    p_MMA845x = new MMA845x(i2c, MMA845x::SA0_VSS);
    //p_MMA845x->attachZAxisPulse(&zTap);
    
    const int ADR = 0x3A;
    char data[2], cmd = 0x0D;
    i2c.write(ADR, &cmd, 1, true);
    i2c.read(ADR, &data[0], 1);  // data[0]: Who am I? 
    
    //p_MMA845x->enableMotionMode();
    //p_MMA845x->registerDump();
    p_MMA845x->enableDataReadyMode();
    
    io.attach(&KeyOn);
}
/*モード決定*/
void GetMode(void)
{
    // 横置きなら時計タイマーモード、縦置きなら計量モード
    //int x = p_MMA845x->getX();
    //int y = p_MMA845x->getY();
    //int z = p_MMA845x->getZ();
    float xx = p_MMA845x->getXX();    
    _mode = (xx < 0.3) ? M_SCALE : M_WATCHTIMER;
#ifdef UART_DEBUG
    pc.printf("KATAMUKI xx=%f, mode=%s\r\n", xx, (_mode == M_SCALE) ? "SCALE" : "WATCHTIMER");
#endif
}
/*STATE決定*/
void GetState(int sw)
{
    ble_date_time_t dt;
    // スイッチ長押しでタイマー、通常押しで時間表示
    if(sw == exio::LongPressed) {
        p_CurrentTimeService->setCounter(0); // タイマーカウンタリセット
        io.displaySeconds(0);
        _state = S_TIMER;
#ifdef UART_DEBUG
        pc.printf("S_TIMER START\r\n");
#endif
    } else if(sw == exio::Pressed){
        p_CurrentTimeService->setTm(60/*sec*/); /*表示タイムアウト*/
        p_CurrentTimeService->readDateTime(dt); // 時計取得
        io.displayHHMM(dt);
        _state = S_WATCH;
#ifdef UART_DEBUG
        pc.printf("S_WATCH START\r\n");
#endif
    }
}
int TMain(int sw)
{
    /*下記は時計/タイマーモード*/
    ble_date_time_t dt;
    int t;
    switch(_state){
        case S_TIMER:
            /*タイマー表示の場合*/
            t = p_CurrentTimeService->getCounter();
            io.displaySeconds(t); // タイマー表示
            // スイッチ押された場合終了
            if(sw != exio::None){
#ifdef UART_DEBUG
                pc.printf("S_TIMER EXIT\r\n");
#endif
                return 1; // モード終了
            }
            break;
        case S_WATCH:
            /*時計表示の場合*/
            p_CurrentTimeService->readDateTime(dt); // 時計取得
            io.displayHHMM(dt); // 時計表示
            // 表示タイムアウトもしくはスイッチ押しの場合終了
            if(/*p_CurrentTimeService->getTm() <= 0 ||*/ sw != exio::None){ // タイムアウトorスイッチ押し
#ifdef UART_DEBUG
                pc.printf("S_WATCH EXIT\r\n");
#endif
                return 1; // モード終了
            }
           break;
        default:
            break;
    }
    return 0; // モード継続
}
/*E-----------------------------------------------------------------------*/

//DigitalOut _reg_ps(P0_1, 1); // 1=normal, 0=power_save
//DigitalOut _adc_rate(P0_6, 1); // 0=10Hz, 1=80Hz (HX711's RATE pin)

int main()
{
/*S----------------------------------------------------*/
    int sw;
/*E----------------------------------------------------*/
    float weight_s;
    int Navg = 5;
    int sample = 0;
#ifdef UART_DEBUG
    pc.baud(UART_BAUD_RATE);
    pc.printf("%s(%d): Program Start\r\n", __FILE__, __LINE__);
    // for checking SPI configuration (SPI1 is used_)
//    pc.printf("SPI->PSELSCK  = %x\r\n", NRF_SPI0->PSELSCK);  // will be 15 (P0_15)
//    pc.printf("SPI->PSELMISO = %x\r\n", NRF_SPI0->PSELMISO); // will be 13 (P0_13)
//    pc.printf("SPI->PSELMOSI = %x\r\n", NRF_SPI0->PSELMOSI); // will be 14 (P0_14): dummy
//    pc.printf("SPI->PSELSCK  = %x\r\n", NRF_SPI1->PSELSCK);  // will be 15 (P0_15)
//    pc.printf("SPI->PSELMISO = %x\r\n", NRF_SPI1->PSELMISO); // will be 13 (P0_13)
//    pc.printf("SPI->PSELMOSI = %x\r\n", NRF_SPI1->PSELMOSI); // will be 14 (P0_14): dummy
#endif
#ifdef PCB_VER3
    // set XTAL=32MHz for TaiyoYuden's module
    //  is moved to mbed-src/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822/system_nrf51.c
    DEBUG("UICR->XTALFREQ=%x\r\n", NRF_UICR->XTALFREQ); // this should be 0xffffff00, not 0xffffffff
#endif

    BleInitialize();
/*S-----------------------------------------------*/
    AccelInit();
/*E-----------------------------------------------*/
    AppInit();

    led_mode = MODE_OFF;
#ifdef DISPLAY_DEMO
    uint16_t d = 0;
    uint8_t demo_count = 0;
    led_mode = MODE_START; // for debug mode
#endif
    for (;; ) {
        // 100msec waitForEvent
        t.reset();
        while(t.read_ms() < LED_INTERVAL_MSEC) {
            t.start();
            ble.waitForEvent();
            t.stop();
        }
        switch(led_mode) {
            case MODE_OFF:
                io.analog_pow(0);
                io.display(0);
/*S--------------------------------------------------------------------*/
                sw = io.get_switch();
                io.switch_reset();
                if(sw != exio::None) {/*通常押しもしくは長押し*/
                    _key1sec = 0;
                    io.CallFlagClear();
                    GetMode(); /*傾きからモード決定*/
                    if(_mode == M_WATCHTIMER){
                        GetState(sw); //WATCH or TIMER ?
                    }
#ifdef UART_DEBUG
                    pc.printf("GO MODE_START\r\n");
#endif
/*E--------------------------------------------------------------------*/
                    led_mode = MODE_START;
                }
/*S---------------------------------------------------------------------------*/
                else {
                    // キー押された状態で1sec経過した場合表示のみ開始、Timerモード開始は後ほど
                    if(_key1sec == 1){
                        _mode = M_WATCHTIMER;
                        _state = S_TIMER;                        
                        io.analog_pow(1);
                        io.power_save_mode(0);
                        _analog_skip = true;
                        io.displaySeconds(0);
                        //io.display_unitT();
                        _key1sec = 2;
                    } else if(_key1sec == 2){
                        led_brightness += BRIGHTNESS_ADDVALUE; // 徐々に明るく
                        io.display(led_brightness);
                        if(led_brightness >= BRIGHTNESS_MAXVALUE) _key1sec = 3;
                    } else {
                        io.display(led_brightness);
                    }
                }
/*E---------------------------------------------------------------------------*/
                break;
            case MODE_START:
                //if(_analog_skip) {_analog_skip=false; goto L090;}
                io.analog_pow(1);
                io.power_save_mode(0);
/*S----------------------------------------------------------------*/
//L090:
                // タイマー時はここで毎回更新
                //if(_mode == M_WATCHTIMER && _state == S_TIMER){
                //    p_CurrentTimeService->setCounter(0); // タイマーカウンタリセット
                //    io.displaySeconds(0);
                /*} else*/ if(_mode == M_SCALE){
                    io.display_value = 0;
                }
/*E----------------------------------------------------------------*/
                led_brightness += BRIGHTNESS_ADDVALUE;
                io.display(led_brightness);
                if(led_brightness >= BRIGHTNESS_MAXVALUE) {
/*S-----------------------------------------------------------------------*/
                    if(_mode == M_WATCHTIMER){
                        ble.startAdvertising();
                        led_mode = MODE_ON;
                        break; /*時間/タイマーモードはここで終了*/
                    }
/*E-----------------------------------------------------------------------*/
                    /*計量モードの初期処理*/
                    update_counter = 0;
                    io.calibrate_weight(); /*ここがゼロ補正*/
#if defined(PCB_VER1) || defined(PCB_VER2)
                    SWInit();
#endif
                    ble.startAdvertising();
                    led_mode = MODE_ON;
                    weight_s = 0.0;
                    sample = 0;
                }
                break;
            case MODE_ON:
#ifdef UART_DEBUG
                //pc.printf("%d %d %.2f\r\n", io.get_switch(), io.get_weight_raw(), io.get_weight());
#endif
                io.analog_pow(1);
#ifdef DISPLAY_DEMO
                demo_count++;
                if (demo_count == 10) {
                    demo_count = 0;
                    io.display_value = d++; // increment display value for every 1s in demo mode
                    weight_data = quick_ieee11073_from_float(d);
                    ble.updateCharacteristicValue(WeightMeasurement.getValueAttribute().getHandle(),
                                                  (uint8_t *)&weight_data,
                                                  sizeof(weight_data));
                }
#else
/*S-------------------------------------------------------------------------*/
                sw = io.get_switch();
                io.switch_reset();
                if(_mode == M_WATCHTIMER){
                    int ret = TMain(sw); // 時間/タイマー処理へ
                    if(ret == 1){ // モード終了
                        goto L010;
                    }
                    break; // 時間/タイマーモードはここで終了
                }
                /*下記は計量モード*/
                if(sw == exio::Pressed) {
L010:
#ifdef UART_DEBUG
                    pc.printf("GO MODE_END\r\n");
#endif
/*E-------------------------------------------------------------------------*/
                    led_mode = MODE_END;
                    if(ble.getGapState().connected) {
                        ble.disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION);
                    } else {
                        ble.stopAdvertising();
                    }
                } else {
                    scale++;
                    ble.updateCharacteristicValue(WeightScale.getValueAttribute().getHandle(),
                                                  (uint8_t *)&scale,
                                                  sizeof(scale));

                    weight_s += io.get_weight();
                    sample++;
                    if (sample == Navg) {
                        weight = weight_s / (float)Navg;
                        io.display_value = (uint16_t)weight;
                        weight_s = 0.0;
                        sample = 0;
#ifdef UART_DEBUG
                        pc.printf("weight=%.1f\r\n", weight);
#endif
                    }
//                    pc.printf("weight=%.1f\r\n", weight);
//                    io.display_value = 8888; // for LED soldering check
#ifdef UART_DEBUG
//                    pc.printf("%d\r\n", io._get_adc_raw(0));
//                    pc.printf("weight=%f %d / %d\r\n", weight, io.display_value, io._adc0);
#endif
                    if(++update_counter >= 5) {
                        weight_data = quick_ieee11073_from_float(weight);
                        ble.updateCharacteristicValue(WeightMeasurement.getValueAttribute().getHandle(),
                                                      (uint8_t *)&weight_data,
                                                      sizeof(weight_data));
                        update_counter = 0;
                    }
                }
#endif
                break;
            case MODE_END:
                led_brightness -= BRIGHTNESS_ADDVALUE;
                io.display(led_brightness);
                if(led_brightness <= BRIGHTNESS_MINVALUE) {
#if defined(PCB_VER1) || defined(PCB_VER2)
                    SWInit();
#endif
                    led_mode = MODE_OFF;
                    io.power_save_mode(1);
                }
                break;
        }
    }
}