Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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(']'); }