Doug Anson / mbedEndpointNetwork_BLE

Dependencies:   libnsdl_m0 BLE_API Base64 nRF51822 SplitterAssembler

bt_network/BleUartRPC/UartRPC.cpp

Committer:
ansond
Date:
2015-07-25
Revision:
33:4f6929e123f2
Parent:
16:fb9c3f2af2df
Child:
35:71eb3663ecbd

File content as of revision 33:4f6929e123f2:

/**
 * @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 "UartRPCFunctions.h"
 #include "Base64.h"
 
 #ifdef DBG
    #undef DBG
 #endif
 #define DBG  std::printf
 
 // immediate response variable pointers...
 uint8_t *_immediate_response_buffer = NULL;
 int      _immediate_response_buffer_length = 0;
 
 // constructor
 UartRPC::UartRPC(BLEDevice &ble) : m_dispatcher(ble), m_recv_accumulator() {
     this->m_recv_raw_data = NULL;
     this->m_recv_raw_data_length = 0;
     this->m_local_dispatch_available = false;
     this->m_location = NULL;
 }
 
 uint8_t __tmp_buffer[MAX_ARGUMENT_LENGTH+1];
 uint8_t base64_buffer[MAX_RESULT_LENGTH+1];
 
 // dispatch RPC
 int UartRPC::dispatch(uint8_t fn_id,void *cb,uint8_t *response,int response_length,const char *format,...)
 {
     // save off the CB if it exists
     this->m_cb = cb;
     
     // serialize the variable arguments into a long string...
     va_list args;
     memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1);
     va_start(args, format);
     vsnprintf((char *)__tmp_buffer,MAX_ARGUMENT_LENGTH,format,args);
     va_end(args);
          
     // dispatch now...
     return this->m_dispatcher.dispatch(fn_id,__tmp_buffer,strlen((char *)__tmp_buffer),response,response_length);
 }
 
 // set the location instance
 void UartRPC::setLocationInstance(BLELocation *location) {
    this->m_location = location;
 }
 
 // dispatch locally
 void UartRPC::dispatch() {
     // assemble the argument buffer...
     memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1);
     int length = this->m_recv_accumulator.assemble(__tmp_buffer,MAX_ARGUMENT_LENGTH);
     
     // DEBUG
     //DBG("UartRPC: dispatch(local): buffer [%s] length=%d\r\n",__tmp_buffer,length);
     
     // parse the buffer
     memset(base64_buffer,0,MAX_RESULT_LENGTH+1);
     int fn_id = 0;
     
     // strip off head,tail and separator, replace with spaces
     int final_length = 0;
     for(int i=0;i<length && final_length == 0;++i) {
         if (__tmp_buffer[i] == '[') __tmp_buffer[i] = ' ';
         if (__tmp_buffer[i] == '|') __tmp_buffer[i] = ' ';
         if (__tmp_buffer[i] == ']') { __tmp_buffer[i] = '\0'; final_length = i; }
     }
     
     // scan over the two values
     sscanf((char *)__tmp_buffer,"%d %s",&fn_id,base64_buffer);
     int base64_buffer_length = strlen((char *)base64_buffer);
     
     // DEBUG
     //DBG("UartRPC: dispatch(local): fn_id = 0x%.2x base64_buffer = [%s] length=%d\r\n",fn_id,base64_buffer,base64_buffer_length);
          
     // invoke the appropriate function
     //DBG("UartRPC: dispatch(local): requested function ID: 0x%.2x...\r\n",fn_id);
     switch(fn_id) {
         case SOCKET_OPEN_FN: {
             // socket open has been attempted... call the CB if it exists and process the status
             //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN length=%d\r\n",base64_buffer_length);
             if (this->m_cb != NULL) {
                 // cast the callback
                 ble_dispatch_callback_fn cb = (ble_dispatch_callback_fn)this->m_cb;
                 
                 // parse the packet received for the status
                 bool open_ok = false;
                 //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN socket  open status: [%s]\r\n",base64_buffer);
                 int int_open_ok = 0;
                 sscanf((char *)base64_buffer,"%d",&int_open_ok);
                 if (int_open_ok == 1) open_ok = true;
                 
                 // invoke the callback with the status
                 //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: invoking socket open callback (status: %d)...\r\n",int_open_ok);
                 cb(open_ok);
                 //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: callback for socket open (status: %d) completed...\r\n",int_open_ok);
             }
             else {
                 // no callback given... so we are stuck...
                 DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN : ERROR no connect() callback function registered!\r\n");
             }
             
             // done with the callback
             this->m_cb = NULL;
             break;
         }
         case GET_LOCATION_FN: {
             // reset our local dispatch
             this->resetLocalDispatch();
             
             // process the location update response... 
             Base64 b64;
             base64_buffer_length = final_length;
             char *location = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length);
             int location_length = base64_buffer_length; // modified by Decode()....
             //DBG("UartRPC: dispatch(local): GET_LOCATION_FN: location(%d): %s\r\n",location_length,location);
             if (this->m_location != NULL) this->m_location->processLocationUpdateResponse(location,location_length);
             
             // local dispatch is now ready...
             this->m_local_dispatch_available = true;
             break;
         }
         case RECV_DATA_FN: {
             // reset our local dispatch
             //DBG("UartRPC: dispatch(local): resetting...\r\n");
             this->resetLocalDispatch();

             // decode the arguments and save off the local dispatch...
             //DBG("UartRPC: dispatch(local): base64 decoding...\r\n");
             Base64 b64;
             base64_buffer_length = final_length;
             this->m_recv_raw_data = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length);
             this->m_recv_raw_data_length = base64_buffer_length; // modified by Decode()....
             
             // only RECV_DATA_FN is local... make it ready for retrieval and flag it as ready...
             //DBG("UartRPC: dispatch(local): RECV_DATA_FN length=%d\r\n",this->m_recv_raw_data_length);
                     
             // local dispatch is now ready...
             this->m_local_dispatch_available = true;
             break;
         }
         default: {
             // all other function ID's are non-local
             DBG("UartRPC: dispatch(local): ignoring non-local function call request (id=0x%.2x)...\r\n",fn_id);
             
             // reset the local dispatch
             this->resetLocalDispatch();
             break;
         }
     }
 }
 
 // is a local dispatch (packet) available?
 bool UartRPC::localDispatchAvailable() { return this->m_local_dispatch_available; };
 
 // reset the local dispatch availability
 void UartRPC::resetLocalDispatch() {
     if (this->m_recv_raw_data != NULL) free(this->m_recv_raw_data);
     this->m_recv_raw_data = NULL;
     this->m_recv_raw_data_length = 0;
     this->m_local_dispatch_available = false;
 }
 
 // transfer the local dispatch and reset
 int UartRPC::retrieveLocalDispatch(uint8_t *buffer,int buffer_length) {
     if (this->m_local_dispatch_available == true) {
         // copy over the dispatch
         memset(buffer,0,buffer_length);
         int length = this->m_recv_raw_data_length;
         if (length > buffer_length) {
             DBG("UartRPC::retrieveLocalDispatch: WARNING: input buffer is too small (is %d bytes, needs to be %d bytes)...\r\n",buffer_length,length);
             length = buffer_length;
         }
         memcpy(buffer,this->m_recv_raw_data,length);
         
         // now reset
         this->resetLocalDispatch();
         
         // return the length
         return length;
     }
     return 0;
 }
 
 // accumulate to dispatch locally... 
 bool UartRPC::accumulate(uint8_t *buffer,int buffer_length) {     
     // add to the accumulator
     this->m_recv_accumulator.add(buffer,buffer_length);
     
     // determine if we have a completed packet by looking for the "tail"
     return this->m_recv_accumulator.hasCollectedCharacter(']');
 }