Doug Anson / mbedEndpointNetwork_BLE

Dependencies:   libnsdl_m0 BLE_API Base64 nRF51822 SplitterAssembler

Files at this revision

API Documentation at this revision

Comitter:
ansond
Date:
Mon Feb 16 06:37:35 2015 +0000
Parent:
4:a3a1bc1718ba
Child:
6:98af441fd960
Commit message:
updates - pre-RPC

Changed in this revision

NSDL/nsdl_support.cpp Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/Buffer.lib Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/Dispatcher.cpp Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/Dispatcher.h Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/UartRPC.cpp Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/UartRPC.h Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/UartRPCFunctions.cpp Show annotated file Show diff for this revision Revisions of this file
bt_network/BleUartRPC/UartRPCFunctions.h Show annotated file Show diff for this revision Revisions of this file
bt_network/SplitterAssembler.lib Show annotated file Show diff for this revision Revisions of this file
network_stubs/network_stubs.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/NSDL/nsdl_support.cpp	Sat Feb 14 08:45:12 2015 +0000
+++ b/NSDL/nsdl_support.cpp	Mon Feb 16 06:37:35 2015 +0000
@@ -137,9 +137,6 @@
         register_endpoint(false);
         DBG("NSP: (re)registering complete.\r\n");
     }
-    else {
-        DBG("NSP: BLE not connected. Skipping re-registration...\r\n");
-    }
 }
 
 void nsdl_init() {    
@@ -194,12 +191,13 @@
         ble.waitForEvent();
         
         // only process if we are registered and thus connected... otherwise ignore
-        if (__registered) {
+        if (__registered == true) {
             //DBG("NSP: waiting for data...\r\n");
             int n = server.receiveFrom(from,nsp_buffer,sizeof(nsp_buffer));
-    
-            //DBG("NSP: received %d bytes... processing..\r\n.",n);
-            if (n >= 0) sn_nsdl_process_coap((uint8_t*)nsp_buffer,n,&received_packet_address);  
+            if (n >= 0) {
+                DBG("NSP: received %d bytes... processing..\r\n.",n);
+                sn_nsdl_process_coap((uint8_t*)nsp_buffer,n,&received_packet_address); 
+            } 
         }      
      }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/Buffer.lib	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/sam_grove/code/Buffer/#7b754354b99c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/Dispatcher.cpp	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,31 @@
+/**
+ * @file    Dispatcher.cpp
+ * @brief   BLE UART RPC dispatcher implmentation
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #include "Dispatcher.h"
+ 
+ // constructor
+ Dispatcher::Dispatcher(BLEDevice &ble,int rxsize,int txsize) : m_uart(ble), m_rxbuf(rxsize), m_txbuf(txsize) {
+ }
+ 
+ // dispatch 
+ bool Dispatcher::dispatch(uint8_t fn_id,uint8_t *args,int args_length,uint8_t *response,int response_length) {
+ }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/Dispatcher.h	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,58 @@
+/**
+ * @file    Dispatcher.h
+ * @brief   BLE UART RPC dispatcher header
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #ifndef __RPC_DISPATCH_H__
+ #define __RPC_DISPATCH_H__
+ 
+ #include "BLEDevice.h"
+ #include "UARTService.h"
+ 
+ #include "Buffer.h"
+ 
+ class Dispatcher {
+     public:
+        /**
+        Default constructor
+        @param ble the BLEDevice instance
+        @param rxsize the size of the receive ring buffer (default is 1024)
+        @param txsize the size of the transmit ring buffer (default is 1024)
+        */
+        Dispatcher(BLEDevice &ble,int rxsize = 1024,int txsize = 1024);
+        
+        /**
+        Dispatch function request with arguments (already serialized and prepared for transport)
+        @param fn_id the identifier for the target remote function to invoke
+        @param args the serialized function argument array list
+        @param args_length the length of the serialized function argument list
+        @param response the received response buffer
+        @param response_length the recieved response buffer length
+        @returns true - dispatch succeeded, false - otherwise
+        */
+        bool dispatch(uint8_t fn_id,uint8_t *args,int args_length,uint8_t *response,int response_length);
+        
+     private:
+        UARTService  m_uart;
+        Buffer<char> m_rxbuf;
+        Buffer<char> m_txbuf;
+ };
+ 
+ #endif // __RPC_DISPATCH_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/UartRPC.cpp	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,49 @@
+/**
+ * @file    UartRPC.cpp
+ * @brief   BLE UART RPC implementation
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #include "UartRPC.h"
+ 
+ #include "Base64.h"
+ 
+ #ifdef DBG
+    #undef DBG
+ #endif
+ #define DBG  std::printf
+ 
+ // constructor
+ UartRPC::UartRPC(BLEDevice &ble) : m_dispatcher(ble) {
+ }
+ 
+ // dispatch RPC
+ bool UartRPC::dispatch(uint8_t fn_id,uint8_t *response,int response_length,const char *format,...)
+ {
+     // serialize the variable arguments into a long string...
+     va_list args;
+     uint8_t buffer[MAX_ARGUMENT_LENGTH+1];
+     memset(buffer,0,sizeof(buffer));
+     va_start(args, format);
+     vsnprintf((char *)buffer,MAX_ARGUMENT_LENGTH,format,args);
+     va_end(args);
+          
+     // dispatch now...
+     return this->m_dispatcher.dispatch(fn_id,buffer,strlen((char *)buffer),response,response_length);
+ }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/UartRPC.h	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,43 @@
+/**
+ * @file    UartRPC.h
+ * @brief   BLE UART RPC header
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #ifndef __UART_RPC_H__
+ #define __UART_RPC_H__
+ 
+ #include "mbed.h"
+ #include <stdarg.h>
+ #include "BLEDevice.h"
+ #include "Dispatcher.h"
+ 
+ #define MAX_ARGUMENT_LENGTH        1024            // longest argument sent as parameter list
+ #define MAX_RESULT_LENGTH          1024            // longest result received 
+ 
+ class UartRPC {
+    public:
+        UartRPC(BLEDevice &ble);
+        bool dispatch(uint8_t fn_id,uint8_t *response,int response_length,const char *format,...);
+    
+    private:
+        Dispatcher m_dispatcher;
+ };
+ 
+ #endif // __UART_RPC_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/UartRPCFunctions.cpp	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,126 @@
+/**
+ * @file    UartRPCFunctions.cpp
+ * @brief   BLE UART RPC stubs implementation
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #include "UartRPCFunctions.h"
+ #include "UartRPC.h"
+ 
+ 
+ #include "Base64.h"
+ 
+ #ifdef DBG
+    #undef DBG
+ #endif
+ #define DBG  std::printf
+ 
+ typedef enum {
+     SOCKET_OPEN_FN  = 0x01,
+     SOCKET_CLOSE_FN = 0x02,
+     SEND_DATA_FN    = 0x04,
+     RECV_DATA_FN    = 0x08,
+     NUM_FNs         = 4
+ } FunctionIDs;
+ 
+ UartRPC *__rpc = NULL;
+ 
+ void ble_rpc_init(BLEDevice &ble) 
+ {
+     if (__rpc == NULL) __rpc = new UartRPC(ble);
+ }
+ 
+ bool ble_rpc_open_udp_socket(char *ip_address,int port) 
+ {
+     bool success = false;
+     uint8_t response[2];
+     memset(response,0,sizeof(response));
+     if (__rpc->dispatch(SOCKET_OPEN_FN,response,sizeof((char *)response),"%s %d",ip_address,port)) {
+         // success
+         int reply = 0;
+         scanf((char *)response,"%d",&reply);
+         if (reply == 1) success = true;
+     }
+     else {
+         // failure
+         DBG("ble_rpc_open_udp_socket: dispatch() failed\r\n");
+     }
+     return success;
+ }
+ 
+ bool ble_rpc_close_udp_socket(void) 
+ {
+     bool success = false;
+     uint8_t response[2];
+     memset(response,0,sizeof(response));
+     if (__rpc->dispatch(SOCKET_CLOSE_FN,response,sizeof((char *)response),"%s","")) {
+         // success
+         int reply = 0;
+         scanf((char *)response,"%d",&reply);
+         if (reply == 1) success = true;
+     }
+     else {
+         // failure
+         DBG("ble_rpc_close_udp_socket: dispatch() failed\r\n");
+     }
+     return success;
+ }
+ 
+ bool ble_rpc_send_data(uint8_t *data,int data_length) 
+ {
+     bool success = false;
+     uint8_t response[2];
+     memset(response,0,sizeof(response));
+     Base64 b64;
+     int base64_data_length = MAX_ARGUMENT_LENGTH;
+     char *base64_data = b64.Encode((char *)data,data_length,(std::size_t *)&base64_data_length);
+     if (__rpc->dispatch(SEND_DATA_FN,response,sizeof((char *)response),"%s",base64_data)) {
+         // success
+         int reply = 0;
+         scanf((char *)response,"%d",&reply);
+         if (reply == 1) success = true;
+     }
+     else {
+         // failure
+         DBG("ble_rpc_send_data: dispatch() failed\r\n");
+     }
+     if (base64_data != NULL) free(base64_data);
+     return success;
+ }
+ 
+ int ble_rpc_recv_data(uint8_t *buffer,int buffer_length)
+ {
+     uint8_t base64_buffer[MAX_RESULT_LENGTH+1];
+     memset(base64_buffer,0,sizeof(base64_buffer));
+     if (__rpc->dispatch(RECV_DATA_FN,base64_buffer,MAX_RESULT_LENGTH,"%s","")) {
+         // success
+         Base64 b64;
+         int base64_length = buffer_length;
+         char *raw_buffer = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_length);
+         memcpy(buffer,raw_buffer,base64_length);
+         if (raw_buffer != NULL) free(raw_buffer);
+         return base64_length;
+     }
+     else {
+         // failure
+         DBG("ble_rpc_recv_data: dispatch() failed\r\n");
+     }
+     return -1;
+ } 
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bt_network/BleUartRPC/UartRPCFunctions.h	Mon Feb 16 06:37:35 2015 +0000
@@ -0,0 +1,34 @@
+/**
+ * @file    UartRPCFunctions.h
+ * @brief   BLE UART RPC stubs header
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #ifndef __UART_RPC_FUNCTIONS_H__
+ #define __UART_RPC_FUNCTIONS_H__
+ 
+ #include "UartRPC.h"
+ 
+ extern "C" void ble_rpc_init(BLEDevice &ble);
+ extern "C" bool ble_rpc_open_udp_socket(char *ip_address,int port);
+ extern "C" bool ble_rpc_close_udp_socket(void);
+ extern "C" bool ble_rpc_send_data(uint8_t *data,int data_length);
+ extern "C" int ble_rpc_recv_data(uint8_t *buffer,int buffer_length);
+ 
+ #endif // __UART_RPC_FUNCTIONS_H__
\ No newline at end of file
--- a/bt_network/SplitterAssembler.lib	Sat Feb 14 08:45:12 2015 +0000
+++ b/bt_network/SplitterAssembler.lib	Mon Feb 16 06:37:35 2015 +0000
@@ -1,1 +1,1 @@
-http://developer.mbed.org/users/ansond/code/SplitterAssembler/#5614523d641b
+http://developer.mbed.org/users/ansond/code/SplitterAssembler/#00f7a99862a3
--- a/network_stubs/network_stubs.cpp	Sat Feb 14 08:45:12 2015 +0000
+++ b/network_stubs/network_stubs.cpp	Mon Feb 16 06:37:35 2015 +0000
@@ -24,6 +24,7 @@
 
 #include "BLEDevice.h"
 #include "UARTService.h"
+
 #include "Base64.h"
 #include "SplitterAssembler.h"
 
@@ -37,8 +38,10 @@
 BLEDevice    ble;
 UARTService *uart = NULL;
 volatile bool __registered = false;
+SplitterAssembler splitter;
+Base64 b64;
 
-static const uint16_t uuid16_list[] = {GattService::UUID_DEVICE_INFORMATION_SERVICE};
+static const uint16_t deviceInfoServiceUUID[] = {GattService::UUID_DEVICE_INFORMATION_SERVICE};
 
 char _ipAddress[IP_ADDRESS_LENGTH];
 int  _ipPort;
@@ -64,7 +67,7 @@
 {
     memset(_connectionRecord,0,MAX_CONNECTION_RECORD_LENGTH+1);
     sprintf(_connectionRecord,"1|%s|%d",_ipAddress,_ipPort);
-    DBG("ble_build_connection_record: Connection Record: %s",_connectionRecord);
+    DBG("ble_build_connection_record: Connect Record: %s\r\n",_connectionRecord);
 }
 
 // build disconnection record
@@ -72,7 +75,7 @@
 {
     memset(_connectionRecord,0,MAX_CONNECTION_RECORD_LENGTH+1);
     printf(_connectionRecord,"0|%s|%d",_ipAddress,_ipPort);
-    DBG("ble_build_disconnection_record: Connection Record: %s",_connectionRecord);
+    DBG("ble_build_disconnection_record: Disconnect Record: %s\r\n",_connectionRecord);
 }
 
 // BLE Disconnection callback
@@ -87,15 +90,16 @@
 // BLE Connection callback
 void ble_connect_callback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *params) 
 {
+    wait_ms(3000);  // wait for 3 seconds... let the gateway register the device completely and get ready to accept data...
+    
     if (__registered == false) {
         DBG("ble_connect_callback: BLE connected! Creating connection record...\r\n");
         ble_build_connection_record();
         DBG("ble_connect_callback: Sending connection record...\r\n");
         ble_send_data((uint8_t *)_connectionRecord,strlen(_connectionRecord),false);
         
-        // wait a bit... let the gateway connect...
-        wait_ms(2000);
-        
+        wait_ms(3000);  // wait for 3 seconds... let the gateway register the device completely and get ready to accept data...
+                
         // NSP registration
         DBG("ble_connect_callback: calling NSP registration...\r\n");
         register_endpoint(true);
@@ -109,6 +113,8 @@
 // send the disconnection record
 void ble_send_disconnection_record()
 {
+    DBG("Building disconnection record...\r\n");
+    ble_build_disconnection_record();
     DBG("Sending disconnection record...\r\n");
     ble_send_data((uint8_t *)_connectionRecord,strlen(_connectionRecord),false);
 }
@@ -117,6 +123,7 @@
 void ble_init(void) 
 {
     // BLE initialization and callback setup
+    __registered = false;
     ble.init();
     ble.onDisconnection(ble_disconnect_callback);
     ble.onConnection(ble_connect_callback);
@@ -129,11 +136,13 @@
     
     DBG("Starting BLE Advertising (%s)...\r\n",endpoint_name);
     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
-    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
+    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
     ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_REMOTE_CONTROL);
     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME,(uint8_t *)endpoint_name,strlen((char *)endpoint_name));
-    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
-    ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,(const uint8_t *)endpoint_name, strlen((char *)endpoint_name));
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,(uint8_t *)deviceInfoServiceUUID, sizeof(deviceInfoServiceUUID));
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID, sizeof(UARTServiceUUID));
+    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));    
     ble.startAdvertising();
 }
 
@@ -150,29 +159,30 @@
     
     if (sendHeader) {
         char header[10];
-        uint8_t buffer[1024];
+        uint8_t buffer[256];
         
-        memset(header,0,10);
-        memset(buffer,0,1024);
+        memset(header,0,sizeof(header));
+        memset(buffer,0,sizeof(buffer));
         
-        Base64 encoder;
-        int b64_data_len = 1024;    // initial sizing for malloc() in Base64...
-        char *b64_data = encoder.Encode((char *)data,data_len,(std::size_t *)&b64_data_len);
+        // Base64 Encode + Add Length Header...
+        int b64_data_len = sizeof(buffer);    // initial sizing for malloc() in Base64...
+        char *b64_data = b64.Encode((char *)data,data_len,(std::size_t *)&b64_data_len);
         sprintf(header,"%d|",b64_data_len);
         int header_length = strlen(header);
         memcpy(buffer,header,header_length);
         memcpy((buffer+header_length),b64_data,b64_data_len);
+        
+        // write if we have a UART...
         if (uart != NULL) {
-            DBG("Output: [%s] length=%d...",buffer,(header_length+b64_data_len));
-            
-            // SPLIT
-            SplitterAssembler splitter;
+            // Split into fragments... 
             int num_fragments = splitter.split(buffer,header_length+b64_data_len);
             sent = 0;
             for(int i=0;i<num_fragments;++i) {
-                sent += uart->write((const void *)splitter.get(i),strlen((char *)splitter.get(i)));
+                int i_sent = uart->write((const void *)splitter.get(i),strlen((char *)splitter.get(i)));
+                int diff = splitter.getSplitLength() - i_sent;
+                sent += i_sent;
+                for(int j=0;j<diff;++j) uart->write((const void *)"\0",1);
             }
-            uart->write("\n",strlen("\n"));
         }
         if (b64_data != NULL) free(b64_data);
     }
@@ -180,7 +190,8 @@
         // plumbing headers are simple and dont need the data length header...
         if (uart != NULL) {
             sent = uart->write((const void *)data,data_len);
-            uart->write("\n",strlen("\n"));
+            int diff = splitter.getSplitLength() - sent;
+            for(int j=0;j<diff;++j) uart->write((const void *)"\0",1);
         }
     }
     
@@ -191,18 +202,65 @@
 // BLE recv data
 int ble_recv_data(uint8_t *buffer,int buffer_len)
 {
+    // initialize...
     int received = 0;
-    memset(buffer,0,buffer_len);
-    if (uart != NULL) received = uart->read(buffer,buffer_len);
-    DBG("in ble_recv_data() buffer_len=%d buffer: [",buffer_len);
-    for(int i=0;i<received;++i) {
-        DBG("%.2x",buffer[i]);
-        if (i < (received-1)) DBG(" ");
+    uint8_t encoded_buffer[1024];
+    memset(encoded_buffer,0,sizeof(encoded_buffer));
+    
+    // receive
+    if (uart != NULL) received = uart->read(encoded_buffer,buffer_len);
+    
+    // look for the length header first
+    for(int i=0;i<received;++i) { 
+        if (encoded_buffer[i] == '|') encoded_buffer[i] = ' ';
     }
-    DBG("] received %d bytes\r\n",received);
-    
-    // return the recieved number of bytes
-    return received;
+    uint8_t tmp_buffer[1024];
+    memset((char *)tmp_buffer,0,sizeof(tmp_buffer));
+    int num_bytes = 0;
+    sscanf((char *)encoded_buffer,"%d %s",&num_bytes,tmp_buffer);
+    if (num_bytes > 0) {
+        DBG("in ble_recv_data(): need to read a total of %d bytes...\r\n",num_bytes);
+        
+        // read more... 
+        num_bytes -= strlen((char *)tmp_buffer);
+        int index = strlen((char *)tmp_buffer);
+        DBG("in ble_recv_data(): Initial buffer: [%s] index=%d, num_bytes=%d\r\n",tmp_buffer,index,num_bytes);
+        for(int i=0;i<num_bytes;++i) {
+            DBG("in ble_recv_data() reading byte %d...\r\n",i);
+            tmp_buffer[index] = uart->_getc();
+            ++index;
+        }
+        
+        buffer_len = strlen((char *)tmp_buffer);
+        memset(encoded_buffer,0,sizeof(encoded_buffer));
+        memcpy(encoded_buffer,tmp_buffer,buffer_len);
+        received = buffer_len;
+        
+        // DEBUG
+        DBG("in ble_recv_data() buffer_len=%d ",buffer_len);
+        DBG("encoded_buffer: [%s](%d) ",encoded_buffer,strlen((char *)encoded_buffer));
+        DBG("received %d bytes\r\n",received);
+        
+        // decode and copy to the input buffer
+        int raw_data_len = buffer_len;    // initial sizing for malloc() in Base64...
+        char *raw_data = b64.Decode((char *)encoded_buffer,received,(std::size_t *)&raw_data_len);
+        
+        // copy...
+        memset(buffer,0,buffer_len);
+        int length = raw_data_len;
+        if (length > buffer_len) length = buffer_len;
+        memcpy(buffer,raw_data,length);
+        
+        // clean up
+        if (raw_data != NULL) free(raw_data);
+        
+        // return the recieved number of bytes
+        return received;
+    }
+    else {
+        DBG("in ble_recv_data() no bytes to read...\r\n");
+        return 0;
+    }
 }
     
 // plumb out the network