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@11:d601b867b297, 2015-02-18 (annotated)
- Committer:
- ansond
- Date:
- Wed Feb 18 19:40:24 2015 +0000
- Revision:
- 11:d601b867b297
- Parent:
- 9:bf0cf5828378
- Child:
- 16:fb9c3f2af2df
clean ups and tweaks
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| ansond | 5:9233e88b9c83 | 1 | /** |
| ansond | 5:9233e88b9c83 | 2 | * @file UartRPC.cpp |
| ansond | 5:9233e88b9c83 | 3 | * @brief BLE UART RPC implementation |
| ansond | 5:9233e88b9c83 | 4 | * @author Doug Anson |
| ansond | 5:9233e88b9c83 | 5 | * @version 1.0 |
| ansond | 5:9233e88b9c83 | 6 | * @see |
| ansond | 5:9233e88b9c83 | 7 | * |
| ansond | 5:9233e88b9c83 | 8 | * Copyright (c) 2014 |
| ansond | 5:9233e88b9c83 | 9 | * |
| ansond | 5:9233e88b9c83 | 10 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| ansond | 5:9233e88b9c83 | 11 | * you may not use this file except in compliance with the License. |
| ansond | 5:9233e88b9c83 | 12 | * You may obtain a copy of the License at |
| ansond | 5:9233e88b9c83 | 13 | * |
| ansond | 5:9233e88b9c83 | 14 | * http://www.apache.org/licenses/LICENSE-2.0 |
| ansond | 5:9233e88b9c83 | 15 | * |
| ansond | 5:9233e88b9c83 | 16 | * Unless required by applicable law or agreed to in writing, software |
| ansond | 5:9233e88b9c83 | 17 | * distributed under the License is distributed on an "AS IS" BASIS, |
| ansond | 5:9233e88b9c83 | 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ansond | 5:9233e88b9c83 | 19 | * See the License for the specific language governing permissions and |
| ansond | 5:9233e88b9c83 | 20 | * limitations under the License. |
| ansond | 5:9233e88b9c83 | 21 | */ |
| ansond | 5:9233e88b9c83 | 22 | |
| ansond | 5:9233e88b9c83 | 23 | #include "UartRPC.h" |
| ansond | 9:bf0cf5828378 | 24 | #include "UartRPCFunctions.h" |
| ansond | 5:9233e88b9c83 | 25 | #include "Base64.h" |
| ansond | 5:9233e88b9c83 | 26 | |
| ansond | 5:9233e88b9c83 | 27 | #ifdef DBG |
| ansond | 5:9233e88b9c83 | 28 | #undef DBG |
| ansond | 5:9233e88b9c83 | 29 | #endif |
| ansond | 5:9233e88b9c83 | 30 | #define DBG std::printf |
| ansond | 5:9233e88b9c83 | 31 | |
| ansond | 5:9233e88b9c83 | 32 | // constructor |
| ansond | 9:bf0cf5828378 | 33 | UartRPC::UartRPC(BLEDevice &ble) : m_dispatcher(ble), m_recv_accumulator() { |
| ansond | 9:bf0cf5828378 | 34 | this->m_recv_raw_data = NULL; |
| ansond | 9:bf0cf5828378 | 35 | this->m_recv_raw_data_length = 0; |
| ansond | 9:bf0cf5828378 | 36 | this->m_local_dispatch_available = false; |
| ansond | 5:9233e88b9c83 | 37 | } |
| ansond | 5:9233e88b9c83 | 38 | |
| ansond | 11:d601b867b297 | 39 | uint8_t __tmp_buffer[MAX_ARGUMENT_LENGTH+1]; |
| ansond | 11:d601b867b297 | 40 | uint8_t base64_buffer[MAX_RESULT_LENGTH+1]; |
| ansond | 11:d601b867b297 | 41 | |
| ansond | 5:9233e88b9c83 | 42 | // dispatch RPC |
| ansond | 11:d601b867b297 | 43 | int UartRPC::dispatch(uint8_t fn_id,void *cb,uint8_t *response,int response_length,const char *format,...) |
| ansond | 5:9233e88b9c83 | 44 | { |
| ansond | 11:d601b867b297 | 45 | // save off the CB if it exists |
| ansond | 11:d601b867b297 | 46 | this->m_cb = cb; |
| ansond | 11:d601b867b297 | 47 | |
| ansond | 5:9233e88b9c83 | 48 | // serialize the variable arguments into a long string... |
| ansond | 5:9233e88b9c83 | 49 | va_list args; |
| ansond | 11:d601b867b297 | 50 | memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1); |
| ansond | 5:9233e88b9c83 | 51 | va_start(args, format); |
| ansond | 11:d601b867b297 | 52 | vsnprintf((char *)__tmp_buffer,MAX_ARGUMENT_LENGTH,format,args); |
| ansond | 5:9233e88b9c83 | 53 | va_end(args); |
| ansond | 5:9233e88b9c83 | 54 | |
| ansond | 5:9233e88b9c83 | 55 | // dispatch now... |
| ansond | 11:d601b867b297 | 56 | return this->m_dispatcher.dispatch(fn_id,__tmp_buffer,strlen((char *)__tmp_buffer),response,response_length); |
| ansond | 9:bf0cf5828378 | 57 | } |
| ansond | 9:bf0cf5828378 | 58 | |
| ansond | 9:bf0cf5828378 | 59 | // dispatch locally |
| ansond | 9:bf0cf5828378 | 60 | void UartRPC::dispatch() { |
| ansond | 9:bf0cf5828378 | 61 | // assemble the argument buffer... |
| ansond | 11:d601b867b297 | 62 | memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1); |
| ansond | 11:d601b867b297 | 63 | int length = this->m_recv_accumulator.assemble(__tmp_buffer,MAX_ARGUMENT_LENGTH); |
| ansond | 9:bf0cf5828378 | 64 | |
| ansond | 9:bf0cf5828378 | 65 | // DEBUG |
| ansond | 11:d601b867b297 | 66 | DBG("UartRPC: dispatch(local): buffer [%s] length=%d\r\n",__tmp_buffer,length); |
| ansond | 9:bf0cf5828378 | 67 | |
| ansond | 9:bf0cf5828378 | 68 | // parse the buffer |
| ansond | 9:bf0cf5828378 | 69 | memset(base64_buffer,0,MAX_RESULT_LENGTH+1); |
| ansond | 9:bf0cf5828378 | 70 | int fn_id = 0; |
| ansond | 9:bf0cf5828378 | 71 | |
| ansond | 9:bf0cf5828378 | 72 | // strip off head,tail and separator, replace with spaces |
| ansond | 9:bf0cf5828378 | 73 | int final_length = 0; |
| ansond | 9:bf0cf5828378 | 74 | for(int i=0;i<length && final_length == 0;++i) { |
| ansond | 11:d601b867b297 | 75 | if (__tmp_buffer[i] == '[') __tmp_buffer[i] = ' '; |
| ansond | 11:d601b867b297 | 76 | if (__tmp_buffer[i] == '|') __tmp_buffer[i] = ' '; |
| ansond | 11:d601b867b297 | 77 | if (__tmp_buffer[i] == ']') { __tmp_buffer[i] = '\0'; final_length = i; } |
| ansond | 9:bf0cf5828378 | 78 | } |
| ansond | 9:bf0cf5828378 | 79 | |
| ansond | 9:bf0cf5828378 | 80 | // scan over the two values |
| ansond | 11:d601b867b297 | 81 | sscanf((char *)__tmp_buffer,"%d %s",&fn_id,base64_buffer); |
| ansond | 9:bf0cf5828378 | 82 | int base64_buffer_length = strlen((char *)base64_buffer); |
| ansond | 9:bf0cf5828378 | 83 | |
| ansond | 9:bf0cf5828378 | 84 | // DEBUG |
| ansond | 11:d601b867b297 | 85 | //DBG("UartRPC: dispatch(local): fn_id = 0x%.2x base64_buffer = [%s] length=%d\r\n",fn_id,base64_buffer,base64_buffer_length); |
| ansond | 11:d601b867b297 | 86 | |
| ansond | 9:bf0cf5828378 | 87 | // invoke the appropriate function |
| ansond | 9:bf0cf5828378 | 88 | DBG("UartRPC: dispatch(local): requested function ID: 0x%.2x...\r\n",fn_id); |
| ansond | 9:bf0cf5828378 | 89 | switch(fn_id) { |
| ansond | 11:d601b867b297 | 90 | case SOCKET_OPEN_FN: { |
| ansond | 11:d601b867b297 | 91 | // socket open has been attempted... call the CB if it exists and process the status |
| ansond | 11:d601b867b297 | 92 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN length=%d\r\n",base64_buffer_length); |
| ansond | 11:d601b867b297 | 93 | if (this->m_cb != NULL) { |
| ansond | 11:d601b867b297 | 94 | // cast the callback |
| ansond | 11:d601b867b297 | 95 | ble_dispatch_callback_fn cb = (ble_dispatch_callback_fn)this->m_cb; |
| ansond | 11:d601b867b297 | 96 | |
| ansond | 11:d601b867b297 | 97 | // parse the packet received for the status |
| ansond | 11:d601b867b297 | 98 | bool open_ok = false; |
| ansond | 11:d601b867b297 | 99 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN socket open status: [%s]\r\n",base64_buffer); |
| ansond | 11:d601b867b297 | 100 | int int_open_ok = 0; |
| ansond | 11:d601b867b297 | 101 | sscanf((char *)base64_buffer,"%d",&int_open_ok); |
| ansond | 11:d601b867b297 | 102 | if (int_open_ok == 1) open_ok = true; |
| ansond | 11:d601b867b297 | 103 | |
| ansond | 11:d601b867b297 | 104 | // invoke the callback with the status |
| ansond | 11:d601b867b297 | 105 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: invoking socket open callback (status: %d)...\r\n",int_open_ok); |
| ansond | 11:d601b867b297 | 106 | cb(open_ok); |
| ansond | 11:d601b867b297 | 107 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: callback for socket open (status: %d) completed...\r\n",int_open_ok); |
| ansond | 11:d601b867b297 | 108 | } |
| ansond | 11:d601b867b297 | 109 | else { |
| ansond | 11:d601b867b297 | 110 | // no callback given... so we are stuck... |
| ansond | 11:d601b867b297 | 111 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN : ERROR no connect() callback function registered!\r\n"); |
| ansond | 11:d601b867b297 | 112 | } |
| ansond | 11:d601b867b297 | 113 | |
| ansond | 11:d601b867b297 | 114 | // done with the callback |
| ansond | 11:d601b867b297 | 115 | this->m_cb = NULL; |
| ansond | 11:d601b867b297 | 116 | break; |
| ansond | 11:d601b867b297 | 117 | } |
| ansond | 9:bf0cf5828378 | 118 | case RECV_DATA_FN: { |
| ansond | 11:d601b867b297 | 119 | // reset our local dispatch |
| ansond | 11:d601b867b297 | 120 | DBG("UartRPC: dispatch(local): resetting...\r\n"); |
| ansond | 11:d601b867b297 | 121 | this->resetLocalDispatch(); |
| ansond | 11:d601b867b297 | 122 | |
| ansond | 11:d601b867b297 | 123 | // decode the arguments and save off the local dispatch... |
| ansond | 11:d601b867b297 | 124 | DBG("UartRPC: dispatch(local): base64 decoding...\r\n"); |
| ansond | 11:d601b867b297 | 125 | Base64 b64; |
| ansond | 11:d601b867b297 | 126 | base64_buffer_length = final_length; |
| ansond | 11:d601b867b297 | 127 | this->m_recv_raw_data = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length); |
| ansond | 11:d601b867b297 | 128 | this->m_recv_raw_data_length = base64_buffer_length; // modified by Decode().... |
| ansond | 11:d601b867b297 | 129 | |
| ansond | 9:bf0cf5828378 | 130 | // only RECV_DATA_FN is local... make it ready for retrieval and flag it as ready... |
| ansond | 11:d601b867b297 | 131 | DBG("UartRPC: dispatch(local): RECV_DATA_FN length=%d\r\n",this->m_recv_raw_data_length); |
| ansond | 9:bf0cf5828378 | 132 | |
| ansond | 9:bf0cf5828378 | 133 | // local dispatch is now ready... |
| ansond | 9:bf0cf5828378 | 134 | this->m_local_dispatch_available = true; |
| ansond | 9:bf0cf5828378 | 135 | break; |
| ansond | 9:bf0cf5828378 | 136 | } |
| ansond | 9:bf0cf5828378 | 137 | default: { |
| ansond | 9:bf0cf5828378 | 138 | // all other function ID's are non-local |
| ansond | 9:bf0cf5828378 | 139 | DBG("UartRPC: dispatch(local): ignoring non-local function call request (id=0x%.2x)...\r\n",fn_id); |
| ansond | 9:bf0cf5828378 | 140 | this->resetLocalDispatch(); |
| ansond | 9:bf0cf5828378 | 141 | break; |
| ansond | 9:bf0cf5828378 | 142 | } |
| ansond | 9:bf0cf5828378 | 143 | } |
| ansond | 9:bf0cf5828378 | 144 | } |
| ansond | 9:bf0cf5828378 | 145 | |
| ansond | 9:bf0cf5828378 | 146 | // is a local dispatch (packet) available? |
| ansond | 9:bf0cf5828378 | 147 | bool UartRPC::localDispatchAvailable() { return this->m_local_dispatch_available; }; |
| ansond | 9:bf0cf5828378 | 148 | |
| ansond | 9:bf0cf5828378 | 149 | // reset the local dispatch availability |
| ansond | 9:bf0cf5828378 | 150 | void UartRPC::resetLocalDispatch() { |
| ansond | 9:bf0cf5828378 | 151 | if (this->m_recv_raw_data != NULL) free(this->m_recv_raw_data); |
| ansond | 9:bf0cf5828378 | 152 | this->m_recv_raw_data = NULL; |
| ansond | 9:bf0cf5828378 | 153 | this->m_recv_raw_data_length = 0; |
| ansond | 9:bf0cf5828378 | 154 | this->m_local_dispatch_available = false; |
| ansond | 9:bf0cf5828378 | 155 | } |
| ansond | 9:bf0cf5828378 | 156 | |
| ansond | 9:bf0cf5828378 | 157 | // transfer the local dispatch and reset |
| ansond | 9:bf0cf5828378 | 158 | int UartRPC::retrieveLocalDispatch(uint8_t *buffer,int buffer_length) { |
| ansond | 9:bf0cf5828378 | 159 | if (this->m_local_dispatch_available == true) { |
| ansond | 9:bf0cf5828378 | 160 | // copy over the dispatch |
| ansond | 9:bf0cf5828378 | 161 | memset(buffer,0,buffer_length); |
| ansond | 9:bf0cf5828378 | 162 | int length = this->m_recv_raw_data_length; |
| ansond | 9:bf0cf5828378 | 163 | if (length > buffer_length) { |
| ansond | 9:bf0cf5828378 | 164 | DBG("UartRPC::retrieveLocalDispatch: WARNING: input buffer is too small (is %d bytes, needs to be %d bytes)...\r\n",buffer_length,length); |
| ansond | 9:bf0cf5828378 | 165 | length = buffer_length; |
| ansond | 9:bf0cf5828378 | 166 | } |
| ansond | 9:bf0cf5828378 | 167 | memcpy(buffer,this->m_recv_raw_data,length); |
| ansond | 9:bf0cf5828378 | 168 | |
| ansond | 9:bf0cf5828378 | 169 | // now reset |
| ansond | 9:bf0cf5828378 | 170 | this->resetLocalDispatch(); |
| ansond | 9:bf0cf5828378 | 171 | |
| ansond | 9:bf0cf5828378 | 172 | // return the length |
| ansond | 9:bf0cf5828378 | 173 | return length; |
| ansond | 9:bf0cf5828378 | 174 | } |
| ansond | 9:bf0cf5828378 | 175 | return 0; |
| ansond | 9:bf0cf5828378 | 176 | } |
| ansond | 9:bf0cf5828378 | 177 | |
| ansond | 9:bf0cf5828378 | 178 | // accumulate to dispatch locally... |
| ansond | 9:bf0cf5828378 | 179 | bool UartRPC::accumulate(uint8_t *buffer,int buffer_length) { |
| ansond | 9:bf0cf5828378 | 180 | // add to the accumulator |
| ansond | 9:bf0cf5828378 | 181 | this->m_recv_accumulator.add(buffer,buffer_length); |
| ansond | 9:bf0cf5828378 | 182 | |
| ansond | 9:bf0cf5828378 | 183 | // determine if we have a completed packet by looking for the "tail" |
| ansond | 9:bf0cf5828378 | 184 | return this->m_recv_accumulator.hasCollectedCharacter(']'); |
| ansond | 5:9233e88b9c83 | 185 | } |