chirimenBLE for TY51822

Dependencies:   mbed BLE_API nRF51822

Revision:
0:6b1b97df8a36
Child:
1:4d21403a5251
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 13 02:05:08 2018 +0000
@@ -0,0 +1,580 @@
+#include "mbed.h"
+#include "BLE.h"
+
+#include "board.h"
+
+#define VERSION_NUM 1 // 2018-11-28
+const static char  DEVICE_NAME[] = "btGPIO2";
+
+#define NEED_CONSOLE_OUTPUT 1 
+/* Set this if you need debug messages on the console;
+ * it will have an impact on code-size and power consumption. */
+
+#if NEED_CONSOLE_OUTPUT
+Serial  pc(DBG_TX, DBG_RX); // TX,RX default 9600bps
+#define DEBUG(...) { pc.printf(__VA_ARGS__); }
+#else
+#define DEBUG(...) /* nothing */
+#endif /* #if NEED_CONSOLE_OUTPUT */
+
+
+#ifdef MICROBIT
+// micro:bit matrix-led
+DigitalOut col0(P0_4, 0);
+#endif
+DigitalOut LED_CONNECT(GPIO_LED_CONNECT);
+
+#define CMD_EXPORT      0x10
+#define CMD_GPIO_WRITE  0x11
+#define CMD_GPIO_READ   0x12
+#define CMD_UNEXPORT    0x13
+#define CMD_GPIO_EVENT  0x14
+#define CMD_I2C_INIT    0x20
+#define CMD_I2C_WRITE   0x21
+#define CMD_I2C_RDBYTE  0x22
+#define CMD_I2C_READ    0x23
+#define CMD_ADC_INPUT   0x30
+#define CMD_ADC_READ    0x31
+
+
+// Bluetooth Low Energy
+BLE ble;
+static Gap::ConnectionParams_t connectionParams;
+
+// I2C 2-waire
+I2C i2c(I2C_SDA,I2C_SCL);
+#define MAX_I2C_TRANSFAR_SIZE 10
+
+// Timer
+Ticker timerTask;
+
+/*
+ * gpio bridge used UUID
+ * ServiceUUID:    928a3d40-e8bf-4b2b-b443-66d2569aed50
+ * NotifyDataUUID: 928a3d41-e8bf-4b2b-b443-66d2569aed50
+ * WriteDataUUID:  928a3d42-e8bf-4b2b-b443-66d2569aed50
+ */
+static const uint8_t UUID_GPIO_SERVICE[]  = {0x92,0x8a,0x3d,0x40,0xe8,0xbf,0x4b,0x2b,0xb4,0x43,0x66,0xd2,0x56,0x9a,0xed,0x50};
+static const uint8_t UUID_ADV_SERVICE[]   = {0x50,0xed,0x9a,0x56,0xd2,0x66,0x43,0xb4,0x2b,0x4b,0xbf,0xe8,0x40,0x3d,0x8a,0x92};
+static const uint8_t UUID_NOTIFY_DATA[]   = {0x92,0x8a,0x3d,0x41,0xe8,0xbf,0x4b,0x2b,0xb4,0x43,0x66,0xd2,0x56,0x9a,0xed,0x50};
+static const uint8_t UUID_WRITE_DATA[]    = {0x92,0x8a,0x3d,0x42,0xe8,0xbf,0x4b,0x2b,0xb4,0x43,0x66,0xd2,0x56,0x9a,0xed,0x50};
+static const uint8_t UUID_STAT_DATA[]     = {0x92,0x8a,0x3d,0x43,0xe8,0xbf,0x4b,0x2b,0xb4,0x43,0x66,0xd2,0x56,0x9a,0xed,0x50};
+
+uint8_t wrtData[20] = {0,};
+GattCharacteristic  gWrtCharacteristic (UUID_WRITE_DATA, wrtData, sizeof(wrtData), sizeof(wrtData),
+        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+uint8_t notifyData[20] = {0,};
+GattCharacteristic  gNotifyCharacteristic (UUID_NOTIFY_DATA, notifyData, sizeof(notifyData), sizeof(notifyData),
+        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+uint8_t statData[20] = {0,0};
+GattCharacteristic  gStatCharacteristic (UUID_STAT_DATA, statData, sizeof(statData), sizeof(statData),
+        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+GattCharacteristic *gGpioChars[] = {&gNotifyCharacteristic,&gWrtCharacteristic,&gStatCharacteristic};
+GattService gGpioService = GattService(UUID_GPIO_SERVICE, gGpioChars, sizeof(gGpioChars) / sizeof(GattCharacteristic *));
+
+int gConnect = 0;
+
+int gCmdLen = 0;
+uint8_t gCmdData[20] = {0,};
+
+int gNotifyLen = 0;
+uint8_t gNotifyData[6] = {0x2,0x0,0x0,0x14,0,0};
+int gScanGPIO = 0;
+
+/* ----GPIO Task----------------------------------------------------------------------- */
+void gpioTask() {
+            
+//    LED_CONNECT = !LED_CONNECT;
+    
+    if (gNotifyLen >0) {  // busy
+        return;
+    }
+
+    for (int i=0; i<sizeof(validGpioPins); i++) {
+        if (eventGpioPins[gScanGPIO] != 0) { // is event pins
+            uint8_t rdGpio = gports[gScanGPIO];
+            if ( currentGpioLevel[gScanGPIO] != rdGpio) {
+                DEBUG("GPIO status chenged port%d:%d\r\n",validGpioPins[gScanGPIO],rdGpio);
+                currentGpioLevel[gScanGPIO] = rdGpio;
+                gNotifyData[4] = gScanGPIO;
+                gNotifyData[5] = rdGpio;
+                gNotifyLen = 6;
+                continue;
+            }
+        }
+        gScanGPIO++;
+        if (gScanGPIO > sizeof(validGpioPins)) {
+            gScanGPIO = 0;
+        }
+    }
+}
+
+void reloadGpioCondition() {
+    for (int i=0; i<sizeof(validGpioPins); i++) {
+        if (eventGpioPins[i] != 0) { // is event pins
+            uint8_t rdGpio = gports[i];
+            currentGpioLevel[i] = rdGpio;
+        }
+    }
+}
+
+void clearEventLists() {
+    for (int i=0; i<sizeof(validGpioPins); i++) {
+        eventGpioPins[i] = 0;
+    }
+}
+
+void initGpio() {
+    for (int i=0; i<sizeof(validGpioPins); i++) {
+        int gpioNum = validGpioPins[i];
+        DEBUG("initGpio() 0x%x\r\n", gpioNum);
+        gports[gpioNum].input();        // 端子を入力モード
+        gports[gpioNum].mode(PullNone); // pullアップ/ダウンなし
+        eventGpioPins[gpioNum] = 0;     // イベント監視対象外
+        reloadGpioCondition(); // 設定を更新
+    }
+}
+
+/* --- BLE callbacks ------------------------------------------------------------------- */
+void onDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)    // Mod
+{
+    DEBUG("Disconnected handle %u, reason %u\r\n", params->handle, params->reason);
+    DEBUG("Restarting the advertising process\r\n");
+    DEBUG("Disconnected!\n\r");
+    timerTask.detach(); // stop timer
+    gConnect = 0;
+    clearEventLists();
+    
+    LED_CONNECT = 0;
+    ble.startAdvertising();
+}
+
+#define BLE_INTERVAL_10MS   8
+#define BLE_INTERVAL_12MS   10
+#define BLE_INTERVAL_20MS   15
+#define BLE_INTERVAL_30MS   23
+#define BLE_INTERVAL_50MS   39
+#define BLE_INTERVAL_62MS   50
+#define BLE_INTERVAL_100MS  78
+#define BLE_INTERVAL_125MS  100
+
+void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params)   //Mod
+{
+    DEBUG("Connected!\n\r");
+    LED_CONNECT = 1;
+    ble.getPreferredConnectionParams(&connectionParams);
+//    connectionParams.minConnectionInterval        = BLE_INTERVAL_10MS;
+    connectionParams.minConnectionInterval        = BLE_INTERVAL_50MS;
+//    connectionParams.minConnectionInterval        = INTERVAL_100MS;
+
+//    connectionParams.maxConnectionInterval        = BLE_INTERVAL_12MS;
+    connectionParams.maxConnectionInterval        = BLE_INTERVAL_62MS;
+//    connectionParams.maxConnectionInterval        = BLE_INTERVAL_125MS;
+    if (ble.updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE) {
+        DEBUG("failed to update connection paramter\r\n");
+    }
+    gConnect = 1;
+    timerTask.attach(&gpioTask, 0.1f); // start interval 100mS timer 
+    
+    // set ready flag
+    statData[0] = 0;
+    statData[1] = VERSION_NUM;
+    ble.gattServer().write(gStatCharacteristic.getValueAttribute().getHandle(), statData, 4);
+
+
+}
+
+void ConnectTimeoutCallback(Gap::TimeoutSource_t source)
+{
+    ble.setAdvertisingTimeout(0); /* 0 is disable the advertising timeout. */
+    ble.startAdvertising();
+}
+
+void DataWrittenCallback(const GattWriteCallbackParams *params)
+{
+    uint8_t *wrtData = (uint8_t *)params->data;
+    uint16_t wrtLen = params->len;
+        
+    memcpy(gCmdData,wrtData,wrtLen);
+    gCmdLen = wrtLen;
+    LED_CONNECT = 0; // busy condition
+
+    DEBUG("rcv\r\n");
+//    DEBUG("DataWrittenCallback() len=%u data=", wrtLen);
+//    for (int i=0; i< wrtLen; i++) {
+//        DEBUG("0x%x,", *wrtData++);
+//    }
+//    DEBUG("\r\n");
+
+}
+
+void UpdatesEnabledCallBack(Gap::Handle_t handle)
+{
+    DEBUG("UpdatesEnabled\n\r");
+    // ユーザ処理コード
+}
+ 
+void UpdatesDisabledCallBack(Gap::Handle_t handle)
+{
+    DEBUG("UpdatesDisabled\n\r");
+    // ユーザ処理コード
+}
+ 
+void DataSentCallback(unsigned count)
+{
+//    DEBUG("DataSentCallback\n\r");
+    // ユーザ処理コード
+}
+
+/* --- test code ----------------------------------------------------------------------- */
+int tako() {
+    i2c.frequency(I2C_SPEED);
+    char wReg[2] = {0x0,0x0};
+    char rReg[2] = {0,0};
+    
+    i2c.start();
+    int val = i2c.write(0x48<<1);
+    i2c.stop();
+    DEBUG("write val %d\r\n",val);
+    
+#if 1
+    if (i2c.write(0x48<<1, wReg, 0) == 0) {
+        DEBUG("write ok\r\n");
+    } else {
+        DEBUG("write NG\r\n");
+    }
+#endif    
+//    i2c.write(0x48, wReg, 1);
+#if 1
+    if (i2c.read(0x48<<1, rReg, 2) == 0) {
+        DEBUG("read ok\r\n");
+    } else {
+        DEBUG("read ng\r\n");
+    }
+
+    DEBUG("read sensor data=");
+    for (int i=0; i< 2; i++) {
+      DEBUG("0x%x,", rReg[i]);
+    }
+    DEBUG("\r\n");
+#endif
+    return 0;
+}
+
+/* --- user task ----------------------------------------------------------------------- */
+int checkGPIO(int gpioNum) {
+    for (int i=0; i<sizeof(validGpioPins); i++) {
+        if (validGpioPins[i] == gpioNum) {
+            return i;
+        }
+    }
+    DEBUG("Invalid GPIO number %d\r\n",gpioNum);
+    return -1;    
+}
+
+// ホストからのコマンドを処理
+void commandTask() {
+    uint8_t response[20] = {1,2,3,4};
+    int responseSize = 5;
+    int gpioNum = -1;
+    char i2cWrBuf[MAX_I2C_TRANSFAR_SIZE] = {0,};
+    char i2cRdBuf[MAX_I2C_TRANSFAR_SIZE] = {0,};
+
+    memcpy(response,gCmdData,4); // コマンドヘッダ部分をレスポンスデータにコピー
+
+    switch (gCmdData[3]) {
+      case CMD_EXPORT: // use GPIO port
+        // input:
+        //  gCmdData[4] : target port number
+        //  gCmdData[5] : 0=outpt 1=input
+        // output:
+        //  response[4] : 1=accept 1=reject
+        gpioNum = checkGPIO(gCmdData[4]);
+        if (gpioNum < 0) {
+            response[4] = 0; // error
+        } else {
+            if (gCmdData[5] == 0) {
+                DEBUG("set GPIO output  %d\r\n",gCmdData[4]);
+                gports[gpioNum] = 0; // inital state low
+                gports[gpioNum].output();
+            } else {
+                DEBUG("set GPIO input %d\r\n",gCmdData[4]);
+                gports[gpioNum].input();
+                gports[gpioNum].mode(PullUp);  // 内蔵プルアップを使う
+                // gports[gpioNum].mode( PullDown );    /  内蔵プルダウンを使う
+                eventGpioPins[gpioNum] = 1; // イベント監視対象
+                reloadGpioCondition();
+            }
+            response[4] = 1; // OK
+        }
+        break;
+
+      case CMD_UNEXPORT: // GPIO port input
+        // input:
+        //  gCmdData[4] : target port number
+        // output:
+        //  response[4] : 1=accept 1=reject
+        gpioNum = checkGPIO(gCmdData[4]);
+        if (gpioNum < 0) {
+            response[4] = 0; // error
+        } else {
+            gports[gpioNum].input(); // 端子を入力として解放
+            gports[gpioNum].mode(PullNone);
+            eventGpioPins[gpioNum] = 0; // イベント監視対象外
+            reloadGpioCondition();
+            response[4] = 1; // OK
+        }
+        break;
+
+      case CMD_GPIO_WRITE: // GPIO port write
+        // input:
+        //  gCmdData[4] : target port number
+        //  gCmdData[5] : 0=low 1=high
+        // output:
+        //  response[4] : 1=accept 0=reject
+        gpioNum = checkGPIO(gCmdData[4]);
+        if (gpioNum < 0) {
+            response[4] = 0; // error
+        } else {
+            gports[gpioNum] = gCmdData[5];
+            response[4] = 1; // OK
+        }                
+        break;
+
+      case CMD_GPIO_READ: // GPIO port write
+        // input:
+        //  gCmdData[4] : target port number
+        // output:
+        //  response[4] : 1=accept 0=reject
+        //  response[5] : port condition 0=low 1=high
+        gpioNum = checkGPIO(gCmdData[4]);
+        if (gpioNum < 0) {
+            response[4] = 0; // error
+        } else {
+            gports[gpioNum] = gCmdData[5];
+            if (gports[gpioNum] ==0) {
+                response[5] = 0; // Low
+            } else {
+                response[5] = 1; // High
+            }
+            response[4] = 1; // OK
+            responseSize += 1;
+        }                
+        break;
+
+      case CMD_I2C_INIT: // I2C test access
+        // input:
+        //  gCmdData[4] : slave I2C address
+        // output:
+        //  response[4] : 1=accept 1=reject
+        i2cWrBuf[0] =0;
+        if (i2c.write(gCmdData[4]<<1, i2cWrBuf, 0) == 0) {
+            response[4] = 1; // OK
+        } else {
+            DEBUG("I2C write error address=%x\r\n",gCmdData[4]);
+            response[4] = 0; // error
+        }
+        break;
+
+      case CMD_I2C_READ: // I2C read
+        // input:
+        //  gCmdData[4] : slave I2C address
+        //  gCmdData[5] : sub-address
+        //  gCmdData[6] : length
+        // output:
+        //  response[4] : read data length / 0=reject
+        //  response[5] : read data
+        if ((gCmdData[6] > MAX_I2C_TRANSFAR_SIZE) || (gCmdData[6] < 1)) {
+            DEBUG("I2C write error invalid length=%d\r\n",gCmdData[6]);
+            response[4] = 0; // error
+            break;
+        }
+        i2cWrBuf[0] = gCmdData[5];
+        if (i2c.write(gCmdData[4]<<1, i2cWrBuf, 1, true) != 0) { // Repeat condision
+            DEBUG("I2C write error address=%x\r\n",gCmdData[4]);
+            response[4] = 0; // error
+            break;
+        }
+        if (i2c.read(gCmdData[4]<<1, i2cRdBuf, gCmdData[6]) != 0) {
+            DEBUG("I2C read error address=%x\r\n",gCmdData[4]);
+            response[4] = 0; // error
+            break;
+        }
+//        DEBUG("I2C read ok\r\n");
+        memcpy(&response[5],i2cRdBuf,gCmdData[6]);
+        response[4] = gCmdData[6]; // read size
+        responseSize += gCmdData[6];
+        break;
+
+      case CMD_I2C_RDBYTE:
+        // input:
+        //  gCmdData[4] : slave I2C address
+        //  gCmdData[5] : length
+        // output:
+        //  response[4] : read data length / 0=reject
+        //  response[5] : read data
+        if ((gCmdData[5] > MAX_I2C_TRANSFAR_SIZE) || (gCmdData[5] < 1)) {
+            DEBUG("I2C write error invalid length=%d\r\n",gCmdData[5]);
+            response[4] = 0; // error
+            break;
+        }
+        if (i2c.read(gCmdData[4]<<1, i2cRdBuf, gCmdData[5]) != 0) {
+            DEBUG("I2C read error address=%x\r\n",gCmdData[4]);
+            response[4] = 0; // error
+            break;
+        }
+//        DEBUG("read ok\r\n");
+        memcpy(&response[5],i2cRdBuf,gCmdData[5]);
+        response[4] = gCmdData[5]; // read size
+        responseSize += gCmdData[5];
+        break;
+
+      case CMD_I2C_WRITE: // I2C write
+        // input:
+        //  gCmdData[4] : slave I2C address
+        //  gCmdData[5] : length
+        //  gCmdData[6] : write data
+        //  gCmdData[7] ...
+        // output:
+        //  response[4] : 1=accept 1=reject
+        if ((gCmdData[5] > MAX_I2C_TRANSFAR_SIZE) || (gCmdData[5] < 1)) {
+            DEBUG("I2C write error invalid length=%d\r\n",gCmdData[5]);
+            response[4] = 0; // error
+            break;
+        }
+        memcpy(i2cWrBuf,&gCmdData[6],gCmdData[5]);
+        if (i2c.write(gCmdData[4]<<1, i2cWrBuf, gCmdData[5]) != 0) { // Repeat condision
+            DEBUG("I2C write error address=%x\r\n",gCmdData[4]);
+            response[4] = 0; // error
+            break;
+        }
+
+        response[4] = gCmdData[5]; // return complite transfar size
+        break;
+
+#if 0
+      case CMD_ADC_INPUT:
+        // input:
+        //  gCmdData[4] : target port number
+        // output:
+        //  response[4] : 1=accept 1=reject
+        gpioNum = checkGPIO(gCmdData[4]);
+        if ((gpioNum < 1) || (gpioNum > 6)) {
+            response[4] = 0; // error
+        } else {
+            gports[gpioNum].input(); // 端子を入力として解放
+            gports[gpioNum].mode(PullNone);
+            eventGpioPins[gpioNum] = 0; // イベント監視対象外
+            reloadGpioCondition();
+            
+            // ADC setting
+            // 10bit Reference internal Bandcap(1.2V)
+            NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
+                (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
+                (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
+                (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
+            response[4] = 1; // OK
+        }
+        break;
+        
+      case CMD_ADC_READ:
+        // input:
+        //  gCmdData[4] : target port number
+        // output:
+        //  response[4] : read data length(fixed 2) / 0=reject
+        //  response[5] : read data(MSB)
+        //  response[6] : read data(LSB)
+        gpioNum = gCmdData[4];
+        if ((gpioNum < 1) || (gpioNum > 6)) {
+            response[4] = 0; // error
+        } else {
+            NRF_ADC->CONFIG     &= ~ADC_CONFIG_PSEL_Msk;
+            NRF_ADC->CONFIG     |= (4 << gpioNum) << ADC_CONFIG_PSEL_Pos;
+            NRF_ADC->TASKS_START = 1;
+            while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {
+            }
+            uint16_t advalue = (uint16_t)NRF_ADC->RESULT; // 10 bit
+            DEBUG("read adc %d =%x\r\n",gpioNum, advalue);
+            response[5] = advalue >> 8;
+            response[6] = advalue && 0xff;
+            responseSize += 2;
+        }
+        break;
+#endif
+              
+      default:
+        DEBUG("unknonwn command =%x\r\n",gCmdData[3]);
+        response[4] = 0; // error
+        break;    
+                
+    }
+
+    DEBUG("reply\r\n");
+//    DEBUG("send Notify len=%u data=", responseSize);
+//    for (int i=0; i< responseSize; i++) {
+//        DEBUG("0x%x,", response[i]);
+//    }
+//    DEBUG("\r\n");
+
+    // send response (notify)
+    ble.gattServer().write(gNotifyCharacteristic.getValueAttribute().getHandle(), response, responseSize);
+    LED_CONNECT = 1; // ready
+
+}
+
+/* --- main code ----------------------------------------------------------------------- */
+int main() {
+    LED_CONNECT = 1;
+    gCmdLen = 0;
+    gConnect = 0;
+    gScanGPIO = 0;
+
+    initGpio();
+    DEBUG("PowerON version %d\n\r",VERSION_NUM);
+    
+    /* Initialise the nRF51822 */
+    ble.init();
+
+    /* Setup The event handlers */
+    ble.onConnection(onConnectionCallback);
+    ble.onDisconnection(onDisconnectionCallback);
+    ble.onTimeout(ConnectTimeoutCallback);
+
+    ble.onDataWritten(DataWrittenCallback);
+    ble.onDataSent(DataSentCallback);
+    ble.onUpdatesEnabled(UpdatesEnabledCallBack);
+    ble.onUpdatesDisabled(UpdatesDisabledCallBack);
+
+
+    /* setup advertising */
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+                                     (const uint8_t *)UUID_ADV_SERVICE, sizeof(UUID_ADV_SERVICE));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME,
+                                     (const uint8_t *)DEVICE_NAME,
+                                     strlen(DEVICE_NAME));
+    ble.gap().setAdvertisingInterval(80); /* 50ms; in multiples of 0.625ms. */
+    ble.gap().startAdvertising();
+    DEBUG("Start Advertising\r\n");
+
+    ble.addService(gGpioService);
+
+// tako();
+    LED_CONNECT = 0;
+    for (;; ) {
+        ble.waitForEvent();
+        if (gCmdLen > 0) {
+            commandTask();
+            gCmdLen =0;
+        } else if (gNotifyLen > 0) {
+            ble.gattServer().write(gNotifyCharacteristic.getValueAttribute().getHandle(), gNotifyData, gNotifyLen);
+            gNotifyLen = 0;
+        }
+    }
+
+}