Port of RedBear BLE Shield Arduino Sketch to RedBear Nano. This firmware enables BLE clients to initialize, read and write Nano pins over the air via Bluetooth, using the same protocol used by Redbear BLE Shield. This enables working with Nano devices from any SAndroidE powered application (http://es3.unibs.it/SAndroidE/).

Dependencies:   BLE_API mbed nRF51822 MbedJSONValue

Files at this revision

API Documentation at this revision

Comitter:
giowild
Date:
Mon Jul 24 09:36:09 2017 +0000
Parent:
1:ff6ec7837f46
Commit message:
initial working version includes:; - changing sampling interval for each pin; - changing delta thresold for each pin; - set pin to group

Changed in this revision

MbedJSONValue.lib Show annotated file Show diff for this revision Revisions of this file
Queue.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONValue.lib	Mon Jul 24 09:36:09 2017 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/samux/code/MbedJSONValue/#10a99cdf7846
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Queue.h	Mon Jul 24 09:36:09 2017 +0000
@@ -0,0 +1,126 @@
+// downloaded from: https://gist.github.com/ArnonEilat/4471278
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define TRUE  1
+#define FALSE   0
+#define QUEUE_STRING_LENGTH 40
+
+/* a link in the queue, holds the info and point to the next Node*/
+typedef struct {
+    int length;
+    char payload[QUEUE_STRING_LENGTH-1];  // null-terminated string, max 256 characters long, this may be JSON or any other format, depending on the application
+} DATA;
+
+typedef struct Node_t {
+    DATA data;
+    struct Node_t *prev;
+} NODE;
+
+/* the HEAD of the Queue, hold the amount of node's that are in the queue*/
+typedef struct Queue {
+    NODE *head;
+    NODE *tail;
+    int size;
+    int limit;
+} Queue;
+
+Queue *ConstructQueue(int limit);
+void DestructQueue(Queue *queue);
+int Enqueue(Queue *pQueue, NODE *item);
+NODE *Dequeue(Queue *pQueue);
+int isEmpty(Queue* pQueue);
+
+Queue *ConstructQueue(int limit) {
+    Queue *queue = (Queue*) malloc(sizeof (Queue));
+    if (queue == NULL) {
+        return NULL;
+    }
+    if (limit <= 0) {
+        limit = 65535;
+    }
+    queue->limit = limit;
+    queue->size = 0;
+    queue->head = NULL;
+    queue->tail = NULL;
+
+    return queue;
+}
+
+void DestructQueue(Queue *queue) {
+    NODE *pN;
+    while (!isEmpty(queue)) {
+        pN = Dequeue(queue);
+        free(pN);
+    }
+    free(queue);
+}
+
+int Enqueue(Queue *pQueue, NODE *item) {
+    /* Bad parameter */
+    if ((pQueue == NULL) || (item == NULL)) {
+        return FALSE;
+    }
+    // if(pQueue->limit != 0)
+    if (pQueue->size >= pQueue->limit) {
+        return FALSE;
+    }
+    /*the queue is empty*/
+    item->prev = NULL;
+    if (pQueue->size == 0) {
+        pQueue->head = item;
+        pQueue->tail = item;
+
+    } else {
+        /*adding item to the end of the queue*/
+        pQueue->tail->prev = item;
+        pQueue->tail = item;
+    }
+    pQueue->size++;
+    return TRUE;
+}
+
+NODE * Dequeue(Queue *pQueue) {
+    /*the queue is empty or bad param*/
+    NODE *item;
+    if (isEmpty(pQueue))
+        return NULL;
+    item = pQueue->head;
+    pQueue->head = (pQueue->head)->prev;
+    pQueue->size--;
+    return item;
+}
+
+int isEmpty(Queue* pQueue) {
+    if (pQueue == NULL) {
+        return FALSE;
+    }
+    if (pQueue->size == 0) {
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+/*
+int main() {
+    int i;
+    Queue *pQ = ConstructQueue(7);
+    NODE *pN;
+
+    for (i = 0; i < 9; i++) {
+        pN = (NODE*) malloc(sizeof (NODE));
+        pN->data.info = 100 + i;
+        Enqueue(pQ, pN);
+    }
+
+    while (!isEmpty(pQ)) {
+        pN = Dequeue(pQ);
+        printf("\nDequeued: %d", pN->data);
+        free(pN);
+    }
+    DestructQueue(pQ);
+    return (EXIT_SUCCESS);
+}
+
+*/
\ No newline at end of file
--- a/main.cpp	Mon Mar 27 12:04:16 2017 +0000
+++ b/main.cpp	Mon Jul 24 09:36:09 2017 +0000
@@ -16,6 +16,11 @@
 
 #include "mbed.h"
 #include "ble/BLE.h"
+//#include "UARTService.h"
+#include "Queue.h"
+
+
+//#define MAX_REPLY_LEN           (UARTService::BLE_UART_SERVICE_MAX_DATA_LEN)
 
 #define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
 #define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
@@ -31,7 +36,15 @@
 #define PIN_SERVO                 4 // digital pin in Servo output mode
 #define PIN_NOTSET                5 // pin not set
 
+#define NO_GROUP                  0 // no_group means that current pin is sampled and transmitted individually
+
+
+#define ANALOG_MAX_VALUE          1024 // this is uint16 max value: 65535
+#define DEFAULT_SAMPLING_INTERVAL 1000   // 1 second
+#define DEFAULT_DELTA             10    // this is uint16 in range [0-65535], 655 is 1% delta
+
 BLE  ble;
+Queue *recvQueue = NULL, *toSendQueue =NULL;
 
 // The Nordic UART Service
 static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
@@ -47,17 +60,33 @@
 GattCharacteristic  rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
 GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};
 GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
+//UARTService *m_uart_service_ptr;
+
 
 static const int maxPins = 30;
 uint8_t pinTypes[maxPins];
+uint8_t pinGroups[maxPins];
 uint16_t prevValues[maxPins];
 
+int pinSamplingIntervals[maxPins];
+int pinTimers[maxPins];
+uint16_t pinDelta[maxPins];
+
 DigitalInOut digitals[] = {P0_0,P0_7,P0_8,P0_9,P0_10,P0_11,P0_15,P0_19,P0_28,P0_29};
 int mapDigitals[] = { 0,-1,-1,-1,-1,-1,-1, 1,2,3,4,5,-1,-1,-1, 6,-1,-1,-1, 7,-1,-1,-1,-1,-1,-1,-1,-1, 8, 9,-1};
 AnalogIn analogs[] = {P0_1, P0_2, P0_3, P0_4, P0_5, P0_6};
 int mapAnalogs[] =  {-1, 0, 1, 2, 3, 4, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
 
 
+
+void enqueueItem(Queue *queue, uint8_t *buf, int len) {
+    NODE *item = NULL;
+    item = (NODE*) malloc(sizeof (NODE));
+    memcpy(item->data.payload, buf, len); 
+    item->data.length = len;
+    Enqueue(queue, item);
+}
+
 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
 {
     //pc.printf("Disconnected \r\n");
@@ -65,23 +94,61 @@
     ble.startAdvertising();
 }
 
-bool initPin(int pin, uint8_t type){
-    bool ret=false;
-    if (pin>=0 && pin<31) {       // "initPin(): Pin number out of bounds"
-        if ((type==PIN_INPUT||type==PIN_OUTPUT) && mapDigitals[pin]>=0) {
-            if (type==PIN_INPUT) digitals[mapDigitals[pin]].input();  // initialize as input
-            if (type==PIN_OUTPUT) digitals[mapDigitals[pin]].output(); // initialize as input
-            pinTypes[pin] = type; // mark the pin as initialized
-            ret =true;
-        } else if (type==PIN_ANALOG && mapAnalogs[pin]>=0) {
-            pinTypes[pin] = type; // mark the pin as initialized
-            ret =true;
+
+NODE *enqItem = NULL;
+int bytesCmd = 0;
+bool endsOnNewLine = true;
+#define NOT_FOUND -1
+
+void WrittenHandler(const GattWriteCallbackParams *params)
+{   
+    uint8_t buf[TXRX_BUF_LEN];
+    uint16_t bytesRead, i;
+
+    if (params->handle == txCharacteristic.getValueAttribute().getHandle()) { 
+        ble.readCharacteristicValue(params->handle, buf, &bytesRead);
+        
+        if (enqItem == NULL){
+            endsOnNewLine = buf[0]=='{';
         }
-    }
-    return ret;
+
+        if (!endsOnNewLine) {
+            enqueueItem(recvQueue, buf, bytesRead);
+        } else {
+            for (i=0; i<bytesRead; i++) {
+                if (endsOnNewLine && (buf[i]=='\n' || bytesCmd>QUEUE_STRING_LENGTH)) {
+                    if (enqItem != NULL && enqItem->data.length>0) {  
+                        // push string to queue
+                        Enqueue(recvQueue, enqItem);
+                    }
+                    enqItem = NULL;                
+                } else {
+                    // enqueue character
+                    if (enqItem == NULL) {
+                        enqItem = (NODE*) malloc(sizeof (NODE));
+                        bytesCmd = 0;
+                    }
+                    enqItem->data.payload[bytesCmd++]=buf[i];
+                    enqItem->data.length = bytesCmd;
+                }
+            }
+        }
+    }   
 }
 
-uint16_t readPin(int pin) {
+uint16_t readPin(uint8_t pin) {
+    uint8_t mode = pinTypes[pin];
+    if (mode==PIN_INPUT) { // exists and is initialized as digital output
+        return digitals[mapDigitals[pin]].read()==0?0:ANALOG_MAX_VALUE;
+    } else if (mode==PIN_OUTPUT) { // exists and is initialized as digital output
+        return digitals[mapDigitals[pin]].read()==0?0:ANALOG_MAX_VALUE;
+    } else if (mode==PIN_ANALOG) { // exists and is initialized as digital output
+        return analogs[mapAnalogs[pin]].read_u16();  // 10 bits only
+    }
+    return 0;
+}
+
+uint16_t readPinOld(int pin) {
     uint8_t mode = pinTypes[pin];
     if (mode==PIN_INPUT) { // exists and is initialized as digital output
         mode = 0;
@@ -100,109 +167,43 @@
     return 0;
 }
 
-void sendPinValue(int pin, uint16_t value) {
+void sendPinValue(uint8_t pin, uint16_t value) {
     uint8_t buf[TXRX_BUF_LEN];
     buf[0]='G';
     buf[1]=pin;
-    buf[2]=(uint8_t)(value>>8); buf[3]=(uint8_t)value;
-    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4);
+    buf[2]=(uint8_t)(value>>8); 
+    buf[3]=  (uint8_t) ((value<<8)>>8);
+    enqueueItem(toSendQueue, buf, 4);
+    /*int len = sprintf((char *)buf,"{\"pin\":%d,\"v\":%4.3f}",pin,(float)value/(float)ANALOG_MAX_VALUE);
+    enqueueItem(toSendQueue,buf, len);*/
+    
     prevValues[pin] = value;
 }
 
-void parseRedBearCmd(){
-    uint8_t buf[TXRX_BUF_LEN];
-    memset(buf, 0, TXRX_BUF_LEN);
-    
-    uint8_t startOffset = txPayload[0]==0?1:0;
-    uint8_t index = startOffset;
-    uint8_t cmd = txPayload[index++], pin=txPayload[index++], mode=PIN_NOTSET;
-    pin = pin>=48?pin-48:pin;
 
-    switch (cmd) {
-        case 'Z':sendPinValue(pin,readPin(pin));
-            break;
-        case 'X':initPin(7, PIN_OUTPUT);
-            break;
-        case 'Y':uint8_t value2write = txPayload[index++]-48;
-                    if (mapDigitals[pin]>=0) {
-                        digitals[mapDigitals[pin]].write(value2write==0?0:1);
-                        sendPinValue(pin,readPin(pin));
-                    }
-            break;
-
-        case 'M': //pc.printf("Querying pin %u mode\n",pin);
-            buf[0]=cmd;
-            buf[1]=pin;
-            buf[2]=pinTypes[pin];
-            ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
-            break;
-            
-        case 'S': // set pin mode
-            mode = txPayload[index++];
-            mode = mode>=48?mode-48:mode;
-            if (initPin(pin, mode)) { // analogs are already initialized
-                sendPinValue(pin,readPin(pin));
-            }
-            break;
-            
-        case 'G': //pc.printf("Reading pin %u\n",pin);
-            switch (pinTypes[pin]) {
-                case PIN_INPUT:
-                case PIN_ANALOG:
-                    sendPinValue(pin,readPin(pin));
-                    break;
-                case PIN_OUTPUT: // TODO: send warning pin not readable (is an output)
-                default:  // TODO: send warning pin not initialized
-                    buf[0]=PIN_NOTSET;
-                    buf[1]=PIN_NOTSET;
-                    buf[2]=PIN_NOTSET;
-                    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
-                    break; 
-            }
-            break; 
-            
-        case 'T':
-            switch (pinTypes[pin]) {
-                case PIN_OUTPUT:
-                    uint8_t value2write = txPayload[index++];
-                    if (mapDigitals[pin]>=0) {
-                        digitals[mapDigitals[pin]].write(value2write==0?0:1);
-                        sendPinValue(pin,readPin(pin));
-                    }
-                    break;
-                case PIN_INPUT: // TODO: send warning pin not writable (is an input) 
-                case PIN_ANALOG: // TODO: send warning pin not writable (is an input) 
-                default:  // TODO: send warning pin not initialized
-                    buf[0]='T';
-                    buf[1]='T';
-                    buf[2]='T';
-                    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3);
-                    break; 
-            }
-            break; 
-            
-        default:
-            // echo received buffer
-            ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), &txPayload[startOffset], strlen((char *)&txPayload[startOffset])); // FIXME
-            break;
-    }   
+void sendGroup(uint8_t groupno) {
+    uint8_t buf[TXRX_BUF_LEN], i=0;
+    buf[i++]='G';
+    for (uint8_t pin=0; pin<maxPins;pin++){
+        if (pinGroups[pin]==groupno) {
+            uint16_t value = readPin(pin);
+            buf[i++] = pin;
+            buf[i++] = (uint8_t)(value>>8); 
+            buf[i++] = (uint8_t) ((value<<8)>>8);
+            prevValues[pin] = value;
+        }
+    }
+    if (i>1) { // at least 1 pin value to send
+        enqueueItem(toSendQueue, buf, i);
+    }
 }
 
-
-void WrittenHandler(const GattWriteCallbackParams *Handler)
-{   
-    uint8_t buf[TXRX_BUF_LEN];
-    uint16_t bytesRead;
-    
-    if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) //only if empty
-    {
-        ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
-        memset(txPayload, 0, TXRX_BUF_LEN);
-        memcpy(txPayload, buf, TXRX_BUF_LEN); 
-        
-        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, bytesRead);
-        parseRedBearCmd();
+bool isInputPin(uint8_t pin) {
+    if (pin<maxPins){
+        uint8_t type = pinTypes[pin];
+        return type==PIN_INPUT||type==PIN_ANALOG;
     }
+    return false;
 }
 
 void m_status_check_handle(void)
@@ -218,15 +219,290 @@
     }
 }
 
+
+static volatile int gcd=-1;
+Ticker *pTicker;
+//Timeout timeout;
+static volatile bool recalcTimer = false;
+static volatile bool triggerSensorPolling = false;
+static volatile bool gcdChanged =false;
+
+int calc_gcd(int n1,int n2) {
+    int lgcd=1;
+    for(int i=2; i <= n1 && i <= n2; ++i)
+    {
+        // Checks if i is factor of both integers
+        if(n1%i==0 && n2%i==0)
+            lgcd = i;
+    }
+    return lgcd;
+}
+
+void check_pin_changed(void) 
+{
+    uint8_t buf[QUEUE_STRING_LENGTH];
+    if (gcd>0) {
+        for (int pin=0; pin<maxPins;pin++){
+            if (isInputPin(pin)) {
+                if (pinTimers[pin] < 0) {
+                    pinTimers[pin] = pinSamplingIntervals[pin];
+                } else {
+                    pinTimers[pin]-=gcd;
+                }
+                if (pinTimers[pin]==0) {
+                    pinTimers[pin] = pinSamplingIntervals[pin];
+                    uint16_t value = readPin(pin);
+                    if (abs(prevValues[pin]-value) >= pinDelta[pin]) {
+                        if (pinGroups[pin]!=NO_GROUP) { // enqueue sending operation for group
+                            int len = sprintf((char *)buf,"R%c",pinGroups[pin]);
+                            enqueueItem(recvQueue, buf, len);                        
+                        } else { // send the pin
+                            sendPinValue(pin,value);    
+                        }
+                    }
+                }
+            }
+        }
+    }  
+}
+
+void calc_timer_interval()
+{
+    gcd = -1;
+    for (int pin=0; pin<maxPins;pin++){
+        if (isInputPin(pin) && pinSamplingIntervals[pin]>0) {
+            uint8_t buf[TXRX_BUF_LEN];
+            int len = sprintf((char *)buf,"TIMER %d@%d",pin,pinSamplingIntervals[pin]);
+            //int len = sprintf((char *)buf,"check-gcd");
+            enqueueItem(toSendQueue, buf, len);
+            
+            if (gcd==-1) {
+                gcd = pinSamplingIntervals[pin];
+            } else {
+                gcd = calc_gcd(gcd,pinSamplingIntervals[pin]);
+            }
+        }
+    }
+}
+
+bool initPin(uint8_t pin, uint8_t type){
+    bool ret=false,wasset=true,armTimer=false;
+   
+    //uint8_t buf[TXRX_BUF_LEN];
+    //buf[0]='Y';buf[1]=pin;buf[2]=type;
+    //int len = sprintf((char *)buf,"ASD%d-%c",pin,pin);
+    //enqueueItem(toSendQueue, buf, 3);    
+    
+    if (pin<maxPins) {       // "initPin(): Pin number out of bounds"
+        wasset = pinTypes[pin]!=PIN_NOTSET;
+        if ((type==PIN_INPUT||type==PIN_OUTPUT) && mapDigitals[pin]>=0) {
+            if (type==PIN_INPUT) digitals[mapDigitals[pin]].input();  // initialize as input
+            if (type==PIN_OUTPUT) digitals[mapDigitals[pin]].output(); // initialize as input
+            pinTypes[pin] = type; // mark the pin as initialized
+            ret =true;
+        } else if (type==PIN_ANALOG && mapAnalogs[pin]>=0) {
+            pinTypes[pin] = type; // mark the pin as initialized
+            ret =true;
+        }
+        if (!wasset && ret && (type==PIN_INPUT||type==PIN_ANALOG)) armTimer=true;
+    }
+    if (armTimer) {
+        pinSamplingIntervals[pin] = DEFAULT_SAMPLING_INTERVAL;
+        //pinTimers[pin]=pinSamplingIntervals[pin];
+        recalcTimer = true;
+    }
+    
+    return ret;
+}
+
+bool initPin(uint8_t pin, uint8_t type, uint8_t group){
+    bool ret = initPin(pin, type);
+    if (ret){
+        pinGroups[pin]=group;
+    }
+    return ret;
+}
+
+void changeDelta(uint8_t pin, uint16_t delta) {
+    uint8_t buf[TXRX_BUF_LEN];
+    int len = sprintf((char *)buf,"DELTA %d@%d",pin,delta);
+    enqueueItem(toSendQueue, buf, len);
+    
+    //float fdelta = delta / ANALOG_MAX_VALUE;
+    if (delta > ANALOG_MAX_VALUE) delta=ANALOG_MAX_VALUE;
+    if (isInputPin(pin)) {
+        pinDelta[pin] = delta;
+    }
+}
+
+void changeDeltaPercent(uint8_t pin, float fdelta) {
+    changeDelta(pin, (uint16_t)(fdelta*ANALOG_MAX_VALUE));
+}
+void changeSamplingInterval(uint8_t pin, int interval) {
+    if (isInputPin(pin)) {
+        pinSamplingIntervals[pin]= interval;
+        recalcTimer = true;
+    }
+}
+
+bool writeDigital(uint8_t pin, bool value){
+    if (mapDigitals[pin]>=0) {
+        digitals[mapDigitals[pin]].write(value?1:0);
+        //sendPinValue(pin,readPin(pin));
+    }
+}
+
+void parseRedBearCmd(uint8_t* cmdString){
+    uint8_t buf[TXRX_BUF_LEN];
+    memset(buf, 0, TXRX_BUF_LEN);
+    int len=0, scanned=-1, sampling=-1;
+    float fdelta=-1; 
+    
+    uint8_t startOffset = cmdString[0]==0?1:0;
+    uint8_t index = startOffset;
+    uint8_t cmd = cmdString[index++], pin=cmdString[index++], mode=PIN_NOTSET, group=NO_GROUP;
+    pin = pin>=48?pin-48:pin;
+
+    switch (cmd) {
+        case '{':
+            //snprintf((char*) buf, MAX_REPLY_LEN, "ERROR: Unknown char\n");
+            //m_uart_service_ptr->writeString((char*)buf);
+            break;
+        case 'Y':
+            uint8_t value2write = cmdString[index++]-48;
+            value2write = value2write>=48?value2write-48:value2write;
+            writeDigital(pin,value2write!=0);
+            break;
+
+        case 'M': //pc.printf("Querying pin %u mode\n",pin);
+            buf[0]=cmd;buf[1]=pin;buf[2]=pinTypes[pin];
+            enqueueItem(toSendQueue, buf, 3);
+            break;
+            
+        case 'S': // set pin mode
+            mode = cmdString[index++];
+            mode = mode>=48?mode-48:mode;
+            group = cmdString[index++];
+            if (initPin(pin, mode, group)) { // analogs are already initialized
+            //if (initPin(pin, mode)) { // analogs are already initialized
+                sendPinValue(pin,readPin(pin));
+            }
+            break;
+            
+        case 'D': // delta to consider value changed (as percentage [0-1] of Voltage range)
+            scanned = sscanf( (char *)&cmdString[2], "%f", &fdelta);
+            
+            if (scanned==1 && fdelta>=0 && fdelta<=1) {
+                len = sprintf((char *)buf,"DELTA%d@%f",(int)pin,fdelta);
+                enqueueItem(toSendQueue, buf, len);
+                changeDeltaPercent(pin, fdelta);
+                /*changeDelta           ( pin,((uint16_t)cmdString[index+0]) << 8  |
+                                            ((uint16_t)cmdString[index+1]) );*/
+            } else {
+                len = sprintf((char *)buf,"DELTA%d@ERR",(int)pin);
+                enqueueItem(toSendQueue, buf, len);
+            }
+            break;
+            
+        case 'I': // sampling interval
+            scanned = sscanf( (char *)&cmdString[2], "%d", &sampling);
+
+            if (scanned==1 && sampling>=0) {
+                len = sprintf((char *)buf,"SAMPL%d@%d",(int)pin,sampling);
+                enqueueItem(toSendQueue, buf, len);
+                changeSamplingInterval( pin, sampling);
+            /*changeSamplingInterval( pin,((int)cmdString[index+0]) << 24 | 
+                                        ((int)cmdString[index+1]) << 16 | 
+                                        ((int)cmdString[index+2]) << 8  |
+                                        ((int)cmdString[index+3]) );*/
+            } else {
+                len = sprintf((char *)buf,"SAMPL%d@ERR",(int)pin);
+                enqueueItem(toSendQueue, buf, len);
+            }
+            break;
+            
+        case 'G': //pc.printf("Reading pin %u\n",pin);
+            switch (pinTypes[pin]) {
+                case PIN_INPUT:
+                case PIN_ANALOG:
+                    sendPinValue(pin,readPin(pin));
+                    break;
+                case PIN_OUTPUT: // TODO: send warning pin not readable (is an output)
+                default:  // TODO: send warning pin not initialized
+                    buf[0]=PIN_NOTSET;buf[1]=PIN_NOTSET;buf[2]=PIN_NOTSET;
+                    enqueueItem(toSendQueue, buf, 3);
+                    break; 
+            }
+            break; 
+            
+        case 'T':
+            switch (pinTypes[pin]) {
+                case PIN_OUTPUT:
+                    uint8_t value2write = cmdString[index++];
+                    if (mapDigitals[pin]>=0) {
+                        digitals[mapDigitals[pin]].write(value2write==0?0:1);
+                        sendPinValue(pin,readPin(pin));
+                    }
+                    break;
+                case PIN_INPUT: // TODO: send warning pin not writable (is an input) 
+                case PIN_ANALOG: // TODO: send warning pin not writable (is an input) 
+                default:  // TODO: send warning pin not initialized
+                    buf[0]='T';buf[1]='T';buf[2]='T';
+                    enqueueItem(toSendQueue, buf, 3);
+                    break; 
+            }
+            break; 
+        case 'R':
+            // pin variable contains the group, not the pin number
+            sendGroup(pin);
+            break;
+        default:
+            // echo received buffer
+            enqueueItem(toSendQueue, &cmdString[startOffset], strlen((char *)&cmdString[startOffset]));
+            break;
+    }   
+}
+
+
+void triggerSensor(){
+    triggerSensorPolling=true;
+}
+
+
+void changeGcdTiming(){
+    /*if (gcdChanged) {
+        gcdChanged =false;
+        if (gcd>0) {
+            pTicker->attach(NULL,5);
+            pTicker->attach(triggerSensor, 0.001*gcd);
+        } else {
+            pTicker->attach(NULL,5);
+        }
+    }*/
+
+    uint8_t buf[TXRX_BUF_LEN];
+    int len = sprintf((char *)buf,"check-gcd %d",gcd);
+    enqueueItem(toSendQueue, buf, len);
+}
+
+
 int main(void)
 {
+    
     for (int i=0;i<maxPins;i++) {
         pinTypes[i] = PIN_NOTSET;
         prevValues[i] = 0;
+        pinSamplingIntervals[i] = -1;
+        pinTimers[i]=-1;
+        pinDelta[i]=DEFAULT_DELTA;
+        pinGroups[i]=NO_GROUP;
     }
+
+    initPin(7,PIN_OUTPUT);
+    initPin(28,PIN_OUTPUT);
+    writeDigital(7,true);
+    writeDigital(28,false);
     
-    //memset(txPayload, 0, TXRX_BUF_LEN);
-
     ble.init();
     ble.onDisconnection(disconnectionCallback);
     ble.onDataWritten(WrittenHandler);  
@@ -245,12 +521,81 @@
     
     ble.startAdvertising(); 
 
+    //ticker.attach(m_status_check_handle, 0.2);
+    
+    // Create a UARTService object (GATT stuff).
+    //UARTService myUartService(ble);
+    //m_uart_service_ptr = &myUartService;
+
     Ticker ticker;
-    ticker.attach(m_status_check_handle, 0.2);
+    //pTicker = &ticker;
+    
+    //Ticker pinTicker;
+    //pinTicker.attach(triggerSensor, 5);
+
+    Ticker gcdTicker;
+    gcdTicker.attach(changeGcdTiming, 5);
+    
+    recvQueue = ConstructQueue(40);
+    toSendQueue = ConstructQueue(40);
+    
+    uint8_t buf[QUEUE_STRING_LENGTH];
+    NODE *deqItem = NULL;
+     /*
+    // set pin 7 as VCC and pin 28 as GND
+    int len = sprintf((char *)buf,"S%c%c",7,1);
+    enqueueItem(recvQueue, buf, len);
+    len = sprintf((char *)buf,"S%c%c",28,1);
+    enqueueItem(recvQueue, buf, len);
+    len = sprintf((char *)buf,"Y%c%c",7,'1');
+    enqueueItem(recvQueue, buf, len);
+    len = sprintf((char *)buf,"Y%c%c",28,'0');
+    enqueueItem(recvQueue, buf, len);*/
     
     while(1)
     {
-        ble.waitForEvent();
+        if (ble.getGapState().connected) {
+            if (recalcTimer) {
+                recalcTimer =false;
+                calc_timer_interval();
+                //gcdChanged =true;
+                if (gcd>0) {
+                    ticker.attach(NULL,5);
+                    ticker.attach(triggerSensor, 0.001*gcd);
+                } else {
+                    ticker.attach(NULL,5);
+                }
+            } else if (!isEmpty(toSendQueue)) {
+                //while (!isEmpty(toSendQueue)) {
+                    deqItem = Dequeue(toSendQueue);
+                    //memset(buf, 0, QUEUE_STRING_LENGTH);  // useless
+                    memcpy(buf, (uint8_t *)deqItem->data.payload, deqItem->data.length); 
+                    ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, deqItem->data.length);
+                    //ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, deqItem->data.length);
+                    free(deqItem);
+                //}
+            } else if (!isEmpty(recvQueue)) {
+                //if (!isEmpty(recvQueue)) {
+                    deqItem = Dequeue(recvQueue);
+                    memset(buf, 0, QUEUE_STRING_LENGTH); // maybe useless: TO CHECK its handling in parseRedBearCmd
+                    memcpy(buf, (uint8_t *)deqItem->data.payload, deqItem->data.length); 
+                    //ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, deqItem->data.length);
+                    //ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, deqItem->data.length);
+                    parseRedBearCmd(buf);
+                    free(deqItem);
+                //}  
+            //} else if (!isEmpty(toSendQueue)) {
+            } else if (triggerSensorPolling) {
+                triggerSensorPolling = false;
+                check_pin_changed();
+            } else {
+                ble.waitForEvent();    
+            }
+        } else {
+            ble.waitForEvent();
+        }
+        
+        
     }
 }