BLE mbed Endpoint network stack for mbedConnectorInterface. The stack makes use of a special BLE Socket abstraction to create socket() semantics over BLE.

Dependencies:   libnsdl_m0 BLE_API Base64 nRF51822 SplitterAssembler

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UartRPC.cpp Source File

UartRPC.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    UartRPC.cpp
00003  * @brief   BLE UART RPC implementation
00004  * @author  Doug Anson
00005  * @version 1.0
00006  * @see     
00007  *
00008  * Copyright (c) 2014
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022  
00023  #include "UartRPC.h"
00024  #include "UartRPCFunctions.h"
00025  #include "Base64.h"
00026  
00027  #ifdef DBG
00028     #undef DBG
00029  #endif
00030  #define DBG  std::printf
00031  
00032  // immediate response variable pointers...
00033  uint8_t *_immediate_response_buffer = NULL;
00034  int      _immediate_response_buffer_length = 0;
00035  
00036  // constructor
00037  UartRPC::UartRPC(BLEDevice &ble) : m_dispatcher(ble), m_recv_accumulator() {
00038      this->m_recv_raw_data = NULL;
00039      this->m_recv_raw_data_length = 0;
00040      this->m_local_dispatch_available = false;
00041      this->m_location = NULL;
00042  }
00043  
00044  uint8_t __tmp_buffer[MAX_ARGUMENT_LENGTH+1];
00045  uint8_t base64_buffer[MAX_RESULT_LENGTH+1];
00046  
00047  // dispatch RPC
00048  int UartRPC::dispatch(uint8_t fn_id,void *cb,uint8_t *response,int response_length,const char *format,...)
00049  {
00050      // save off the CB if it exists
00051      this->m_cb = cb;
00052      
00053      // serialize the variable arguments into a long string...
00054      va_list args;
00055      memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1);
00056      va_start(args, format);
00057      vsnprintf((char *)__tmp_buffer,MAX_ARGUMENT_LENGTH,format,args);
00058      va_end(args);
00059           
00060      // dispatch now...
00061      return this->m_dispatcher.dispatch(fn_id,__tmp_buffer,strlen((char *)__tmp_buffer),response,response_length);
00062  }
00063  
00064  // set the location instance
00065  void UartRPC::setLocationInstance(BLELocation *location) {
00066     this->m_location = location;
00067  }
00068  
00069  // dispatch locally
00070  void UartRPC::dispatch() {
00071      // assemble the argument buffer...
00072      memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1);
00073      int length = this->m_recv_accumulator.assemble(__tmp_buffer,MAX_ARGUMENT_LENGTH);
00074      
00075      // DEBUG
00076      //DBG("UartRPC: dispatch(local): buffer [%s] length=%d\r\n",__tmp_buffer,length);
00077      
00078      // parse the buffer
00079      memset(base64_buffer,0,MAX_RESULT_LENGTH+1);
00080      int fn_id = 0;
00081      
00082      // strip off head,tail and separator, replace with spaces
00083      int final_length = 0;
00084      for(int i=0;i<length && final_length == 0;++i) {
00085          if (__tmp_buffer[i] == '[') __tmp_buffer[i] = ' ';
00086          if (__tmp_buffer[i] == '|') __tmp_buffer[i] = ' ';
00087          if (__tmp_buffer[i] == ']') { __tmp_buffer[i] = '\0'; final_length = i; }
00088      }
00089      
00090      // scan over the two values
00091      sscanf((char *)__tmp_buffer,"%d %s",&fn_id,base64_buffer);
00092      int base64_buffer_length = strlen((char *)base64_buffer);
00093      
00094      // DEBUG
00095      //DBG("UartRPC: dispatch(local): fn_id = 0x%.2x base64_buffer = [%s] length=%d\r\n",fn_id,base64_buffer,base64_buffer_length);
00096           
00097      // invoke the appropriate function
00098      //DBG("UartRPC: dispatch(local): requested function ID: 0x%.2x...\r\n",fn_id);
00099      switch(fn_id) {
00100          case SOCKET_OPEN_FN: {
00101              // socket open has been attempted... call the CB if it exists and process the status
00102              //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN length=%d\r\n",base64_buffer_length);
00103              if (this->m_cb != NULL) { 
00104                  // cast the callback
00105                  ble_dispatch_callback_fn cb = (ble_dispatch_callback_fn)this->m_cb;
00106                  
00107                  // parse the packet received for the status
00108                  bool open_ok = false;
00109                  //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN socket  open status: [%s]\r\n",base64_buffer);
00110                  int int_open_ok = 0;
00111                  sscanf((char *)base64_buffer,"%d",&int_open_ok);
00112                  if (int_open_ok == 1) open_ok = true;
00113                  
00114                  // invoke the callback with the status
00115                  //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: invoking socket open callback (status: %d)...\r\n",int_open_ok);
00116                  cb(open_ok);
00117                  //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: callback for socket open (status: %d) completed...\r\n",int_open_ok);
00118              }
00119              else {
00120                  // no callback given... so we are stuck...
00121                  DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN : ERROR no connect() callback function registered!\r\n");
00122              }
00123              
00124              // done with the callback
00125              this->m_cb = NULL;
00126              break;
00127          }
00128          case GET_LOCATION_FN: {
00129              // reset our local dispatch
00130              this->resetLocalDispatch();
00131              
00132              // process the location update response... 
00133              Base64 b64;
00134              base64_buffer_length = final_length;
00135              char *location = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length);
00136              int location_length = base64_buffer_length; // modified by Decode()....
00137              //DBG("UartRPC: dispatch(local): GET_LOCATION_FN: location(%d): %s\r\n",location_length,location);
00138              if (this->m_location != NULL) this->m_location->processLocationUpdateResponse(location,location_length);
00139              
00140              // local dispatch is now ready...
00141              this->m_local_dispatch_available = true;
00142              break;
00143          }
00144          case RECV_DATA_FN: {
00145              // reset our local dispatch
00146              //DBG("UartRPC: dispatch(local): resetting...\r\n");
00147              this->resetLocalDispatch();
00148 
00149              // decode the arguments and save off the local dispatch...
00150              //DBG("UartRPC: dispatch(local): base64 decoding...\r\n");
00151              Base64 b64;
00152              base64_buffer_length = final_length;
00153              this->m_recv_raw_data = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length);
00154              this->m_recv_raw_data_length = base64_buffer_length; // modified by Decode()....
00155              
00156              // only RECV_DATA_FN is local... make it ready for retrieval and flag it as ready...
00157              //DBG("UartRPC: dispatch(local): RECV_DATA_FN length=%d\r\n",this->m_recv_raw_data_length);
00158                      
00159              // local dispatch is now ready...
00160              this->m_local_dispatch_available = true;
00161              break;
00162          }
00163          default: {
00164              // all other function ID's are non-local
00165              DBG("UartRPC: dispatch(local): ignoring non-local function call request (id=0x%.2x)...\r\n",fn_id);
00166              
00167              // reset the local dispatch
00168              this->resetLocalDispatch();
00169              break;
00170          }
00171      }
00172  }
00173  
00174  // is a local dispatch (packet) available?
00175  bool UartRPC::localDispatchAvailable() { return this->m_local_dispatch_available; };
00176  
00177  // reset the local dispatch availability
00178  void UartRPC::resetLocalDispatch() {
00179      if (this->m_recv_raw_data != NULL) free(this->m_recv_raw_data);
00180      this->m_recv_raw_data = NULL;
00181      this->m_recv_raw_data_length = 0;
00182      this->m_local_dispatch_available = false;
00183  }
00184  
00185  // transfer the local dispatch and reset
00186  int UartRPC::retrieveLocalDispatch(uint8_t *buffer,int buffer_length) {
00187      if (this->m_local_dispatch_available == true) {
00188          // copy over the dispatch
00189          memset(buffer,0,buffer_length);
00190          int length = this->m_recv_raw_data_length;
00191          if (length > buffer_length) {
00192              DBG("UartRPC::retrieveLocalDispatch: WARNING: input buffer is too small (is %d bytes, needs to be %d bytes)...\r\n",buffer_length,length);
00193              length = buffer_length;
00194          }
00195          memcpy(buffer,this->m_recv_raw_data,length);
00196          
00197          // now reset
00198          this->resetLocalDispatch();
00199          
00200          // return the length
00201          return length;
00202      }
00203      return 0;
00204  }
00205  
00206  // accumulate to dispatch locally... 
00207  bool UartRPC::accumulate(uint8_t *buffer,int buffer_length) {  
00208      //DBG("UartRPC:: accumulating... [%s] length=%d bytes...\r\n",buffer,buffer_length);
00209         
00210      // add to the accumulator
00211      this->m_recv_accumulator.add(buffer,buffer_length);
00212      
00213      // determine if we have a completed packet by looking for the "tail"
00214      return this->m_recv_accumulator.hasCollectedCharacter(']');
00215  }