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-02-18
- Revision:
- 11:d601b867b297
- Parent:
- 9:bf0cf5828378
- Child:
- 16:fb9c3f2af2df
File content as of revision 11:d601b867b297:
/**
* @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
// 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;
}
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);
}
// 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 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);
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(']');
}