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@35:71eb3663ecbd, 2015-09-04 (annotated)
- Committer:
- ansond
- Date:
- Fri Sep 04 21:04:08 2015 +0000
- Revision:
- 35:71eb3663ecbd
- Parent:
- 33:4f6929e123f2
- Child:
- 36:aa73681951ad
update for android 5.x. A wait() call is necessary for 5.x prior to write().
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 | 33:4f6929e123f2 | 32 | // immediate response variable pointers... |
ansond | 33:4f6929e123f2 | 33 | uint8_t *_immediate_response_buffer = NULL; |
ansond | 33:4f6929e123f2 | 34 | int _immediate_response_buffer_length = 0; |
ansond | 33:4f6929e123f2 | 35 | |
ansond | 5:9233e88b9c83 | 36 | // constructor |
ansond | 9:bf0cf5828378 | 37 | UartRPC::UartRPC(BLEDevice &ble) : m_dispatcher(ble), m_recv_accumulator() { |
ansond | 9:bf0cf5828378 | 38 | this->m_recv_raw_data = NULL; |
ansond | 9:bf0cf5828378 | 39 | this->m_recv_raw_data_length = 0; |
ansond | 9:bf0cf5828378 | 40 | this->m_local_dispatch_available = false; |
ansond | 33:4f6929e123f2 | 41 | this->m_location = NULL; |
ansond | 5:9233e88b9c83 | 42 | } |
ansond | 5:9233e88b9c83 | 43 | |
ansond | 11:d601b867b297 | 44 | uint8_t __tmp_buffer[MAX_ARGUMENT_LENGTH+1]; |
ansond | 11:d601b867b297 | 45 | uint8_t base64_buffer[MAX_RESULT_LENGTH+1]; |
ansond | 11:d601b867b297 | 46 | |
ansond | 5:9233e88b9c83 | 47 | // dispatch RPC |
ansond | 11:d601b867b297 | 48 | int UartRPC::dispatch(uint8_t fn_id,void *cb,uint8_t *response,int response_length,const char *format,...) |
ansond | 5:9233e88b9c83 | 49 | { |
ansond | 11:d601b867b297 | 50 | // save off the CB if it exists |
ansond | 11:d601b867b297 | 51 | this->m_cb = cb; |
ansond | 11:d601b867b297 | 52 | |
ansond | 5:9233e88b9c83 | 53 | // serialize the variable arguments into a long string... |
ansond | 5:9233e88b9c83 | 54 | va_list args; |
ansond | 11:d601b867b297 | 55 | memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1); |
ansond | 5:9233e88b9c83 | 56 | va_start(args, format); |
ansond | 11:d601b867b297 | 57 | vsnprintf((char *)__tmp_buffer,MAX_ARGUMENT_LENGTH,format,args); |
ansond | 5:9233e88b9c83 | 58 | va_end(args); |
ansond | 5:9233e88b9c83 | 59 | |
ansond | 5:9233e88b9c83 | 60 | // dispatch now... |
ansond | 11:d601b867b297 | 61 | return this->m_dispatcher.dispatch(fn_id,__tmp_buffer,strlen((char *)__tmp_buffer),response,response_length); |
ansond | 9:bf0cf5828378 | 62 | } |
ansond | 9:bf0cf5828378 | 63 | |
ansond | 33:4f6929e123f2 | 64 | // set the location instance |
ansond | 33:4f6929e123f2 | 65 | void UartRPC::setLocationInstance(BLELocation *location) { |
ansond | 33:4f6929e123f2 | 66 | this->m_location = location; |
ansond | 33:4f6929e123f2 | 67 | } |
ansond | 33:4f6929e123f2 | 68 | |
ansond | 9:bf0cf5828378 | 69 | // dispatch locally |
ansond | 9:bf0cf5828378 | 70 | void UartRPC::dispatch() { |
ansond | 9:bf0cf5828378 | 71 | // assemble the argument buffer... |
ansond | 11:d601b867b297 | 72 | memset(__tmp_buffer,0,MAX_ARGUMENT_LENGTH+1); |
ansond | 11:d601b867b297 | 73 | int length = this->m_recv_accumulator.assemble(__tmp_buffer,MAX_ARGUMENT_LENGTH); |
ansond | 9:bf0cf5828378 | 74 | |
ansond | 9:bf0cf5828378 | 75 | // DEBUG |
ansond | 16:fb9c3f2af2df | 76 | //DBG("UartRPC: dispatch(local): buffer [%s] length=%d\r\n",__tmp_buffer,length); |
ansond | 9:bf0cf5828378 | 77 | |
ansond | 9:bf0cf5828378 | 78 | // parse the buffer |
ansond | 9:bf0cf5828378 | 79 | memset(base64_buffer,0,MAX_RESULT_LENGTH+1); |
ansond | 9:bf0cf5828378 | 80 | int fn_id = 0; |
ansond | 9:bf0cf5828378 | 81 | |
ansond | 9:bf0cf5828378 | 82 | // strip off head,tail and separator, replace with spaces |
ansond | 9:bf0cf5828378 | 83 | int final_length = 0; |
ansond | 9:bf0cf5828378 | 84 | for(int i=0;i<length && final_length == 0;++i) { |
ansond | 11:d601b867b297 | 85 | if (__tmp_buffer[i] == '[') __tmp_buffer[i] = ' '; |
ansond | 11:d601b867b297 | 86 | if (__tmp_buffer[i] == '|') __tmp_buffer[i] = ' '; |
ansond | 11:d601b867b297 | 87 | if (__tmp_buffer[i] == ']') { __tmp_buffer[i] = '\0'; final_length = i; } |
ansond | 9:bf0cf5828378 | 88 | } |
ansond | 9:bf0cf5828378 | 89 | |
ansond | 9:bf0cf5828378 | 90 | // scan over the two values |
ansond | 11:d601b867b297 | 91 | sscanf((char *)__tmp_buffer,"%d %s",&fn_id,base64_buffer); |
ansond | 9:bf0cf5828378 | 92 | int base64_buffer_length = strlen((char *)base64_buffer); |
ansond | 9:bf0cf5828378 | 93 | |
ansond | 9:bf0cf5828378 | 94 | // DEBUG |
ansond | 11:d601b867b297 | 95 | //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 | 96 | |
ansond | 9:bf0cf5828378 | 97 | // invoke the appropriate function |
ansond | 16:fb9c3f2af2df | 98 | //DBG("UartRPC: dispatch(local): requested function ID: 0x%.2x...\r\n",fn_id); |
ansond | 9:bf0cf5828378 | 99 | switch(fn_id) { |
ansond | 11:d601b867b297 | 100 | case SOCKET_OPEN_FN: { |
ansond | 11:d601b867b297 | 101 | // socket open has been attempted... call the CB if it exists and process the status |
ansond | 16:fb9c3f2af2df | 102 | //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN length=%d\r\n",base64_buffer_length); |
ansond | 11:d601b867b297 | 103 | if (this->m_cb != NULL) { |
ansond | 11:d601b867b297 | 104 | // cast the callback |
ansond | 11:d601b867b297 | 105 | ble_dispatch_callback_fn cb = (ble_dispatch_callback_fn)this->m_cb; |
ansond | 11:d601b867b297 | 106 | |
ansond | 11:d601b867b297 | 107 | // parse the packet received for the status |
ansond | 11:d601b867b297 | 108 | bool open_ok = false; |
ansond | 16:fb9c3f2af2df | 109 | //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN socket open status: [%s]\r\n",base64_buffer); |
ansond | 11:d601b867b297 | 110 | int int_open_ok = 0; |
ansond | 11:d601b867b297 | 111 | sscanf((char *)base64_buffer,"%d",&int_open_ok); |
ansond | 11:d601b867b297 | 112 | if (int_open_ok == 1) open_ok = true; |
ansond | 11:d601b867b297 | 113 | |
ansond | 11:d601b867b297 | 114 | // invoke the callback with the status |
ansond | 16:fb9c3f2af2df | 115 | //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: invoking socket open callback (status: %d)...\r\n",int_open_ok); |
ansond | 11:d601b867b297 | 116 | cb(open_ok); |
ansond | 16:fb9c3f2af2df | 117 | //DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN: callback for socket open (status: %d) completed...\r\n",int_open_ok); |
ansond | 11:d601b867b297 | 118 | } |
ansond | 11:d601b867b297 | 119 | else { |
ansond | 11:d601b867b297 | 120 | // no callback given... so we are stuck... |
ansond | 11:d601b867b297 | 121 | DBG("UartRPC: dispatch(local): SOCKET_OPEN_FN : ERROR no connect() callback function registered!\r\n"); |
ansond | 11:d601b867b297 | 122 | } |
ansond | 11:d601b867b297 | 123 | |
ansond | 11:d601b867b297 | 124 | // done with the callback |
ansond | 11:d601b867b297 | 125 | this->m_cb = NULL; |
ansond | 11:d601b867b297 | 126 | break; |
ansond | 11:d601b867b297 | 127 | } |
ansond | 33:4f6929e123f2 | 128 | case GET_LOCATION_FN: { |
ansond | 33:4f6929e123f2 | 129 | // reset our local dispatch |
ansond | 33:4f6929e123f2 | 130 | this->resetLocalDispatch(); |
ansond | 33:4f6929e123f2 | 131 | |
ansond | 33:4f6929e123f2 | 132 | // process the location update response... |
ansond | 33:4f6929e123f2 | 133 | Base64 b64; |
ansond | 33:4f6929e123f2 | 134 | base64_buffer_length = final_length; |
ansond | 33:4f6929e123f2 | 135 | char *location = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length); |
ansond | 33:4f6929e123f2 | 136 | int location_length = base64_buffer_length; // modified by Decode().... |
ansond | 33:4f6929e123f2 | 137 | //DBG("UartRPC: dispatch(local): GET_LOCATION_FN: location(%d): %s\r\n",location_length,location); |
ansond | 33:4f6929e123f2 | 138 | if (this->m_location != NULL) this->m_location->processLocationUpdateResponse(location,location_length); |
ansond | 33:4f6929e123f2 | 139 | |
ansond | 33:4f6929e123f2 | 140 | // local dispatch is now ready... |
ansond | 33:4f6929e123f2 | 141 | this->m_local_dispatch_available = true; |
ansond | 33:4f6929e123f2 | 142 | break; |
ansond | 33:4f6929e123f2 | 143 | } |
ansond | 9:bf0cf5828378 | 144 | case RECV_DATA_FN: { |
ansond | 11:d601b867b297 | 145 | // reset our local dispatch |
ansond | 16:fb9c3f2af2df | 146 | //DBG("UartRPC: dispatch(local): resetting...\r\n"); |
ansond | 11:d601b867b297 | 147 | this->resetLocalDispatch(); |
ansond | 11:d601b867b297 | 148 | |
ansond | 11:d601b867b297 | 149 | // decode the arguments and save off the local dispatch... |
ansond | 16:fb9c3f2af2df | 150 | //DBG("UartRPC: dispatch(local): base64 decoding...\r\n"); |
ansond | 11:d601b867b297 | 151 | Base64 b64; |
ansond | 11:d601b867b297 | 152 | base64_buffer_length = final_length; |
ansond | 11:d601b867b297 | 153 | this->m_recv_raw_data = b64.Decode((char *)base64_buffer,strlen((char *)base64_buffer),(std::size_t *)&base64_buffer_length); |
ansond | 11:d601b867b297 | 154 | this->m_recv_raw_data_length = base64_buffer_length; // modified by Decode().... |
ansond | 11:d601b867b297 | 155 | |
ansond | 9:bf0cf5828378 | 156 | // only RECV_DATA_FN is local... make it ready for retrieval and flag it as ready... |
ansond | 16:fb9c3f2af2df | 157 | //DBG("UartRPC: dispatch(local): RECV_DATA_FN length=%d\r\n",this->m_recv_raw_data_length); |
ansond | 9:bf0cf5828378 | 158 | |
ansond | 9:bf0cf5828378 | 159 | // local dispatch is now ready... |
ansond | 9:bf0cf5828378 | 160 | this->m_local_dispatch_available = true; |
ansond | 9:bf0cf5828378 | 161 | break; |
ansond | 9:bf0cf5828378 | 162 | } |
ansond | 9:bf0cf5828378 | 163 | default: { |
ansond | 9:bf0cf5828378 | 164 | // all other function ID's are non-local |
ansond | 9:bf0cf5828378 | 165 | DBG("UartRPC: dispatch(local): ignoring non-local function call request (id=0x%.2x)...\r\n",fn_id); |
ansond | 33:4f6929e123f2 | 166 | |
ansond | 33:4f6929e123f2 | 167 | // reset the local dispatch |
ansond | 9:bf0cf5828378 | 168 | this->resetLocalDispatch(); |
ansond | 9:bf0cf5828378 | 169 | break; |
ansond | 9:bf0cf5828378 | 170 | } |
ansond | 9:bf0cf5828378 | 171 | } |
ansond | 9:bf0cf5828378 | 172 | } |
ansond | 9:bf0cf5828378 | 173 | |
ansond | 9:bf0cf5828378 | 174 | // is a local dispatch (packet) available? |
ansond | 9:bf0cf5828378 | 175 | bool UartRPC::localDispatchAvailable() { return this->m_local_dispatch_available; }; |
ansond | 9:bf0cf5828378 | 176 | |
ansond | 9:bf0cf5828378 | 177 | // reset the local dispatch availability |
ansond | 9:bf0cf5828378 | 178 | void UartRPC::resetLocalDispatch() { |
ansond | 9:bf0cf5828378 | 179 | if (this->m_recv_raw_data != NULL) free(this->m_recv_raw_data); |
ansond | 9:bf0cf5828378 | 180 | this->m_recv_raw_data = NULL; |
ansond | 9:bf0cf5828378 | 181 | this->m_recv_raw_data_length = 0; |
ansond | 9:bf0cf5828378 | 182 | this->m_local_dispatch_available = false; |
ansond | 9:bf0cf5828378 | 183 | } |
ansond | 9:bf0cf5828378 | 184 | |
ansond | 9:bf0cf5828378 | 185 | // transfer the local dispatch and reset |
ansond | 9:bf0cf5828378 | 186 | int UartRPC::retrieveLocalDispatch(uint8_t *buffer,int buffer_length) { |
ansond | 9:bf0cf5828378 | 187 | if (this->m_local_dispatch_available == true) { |
ansond | 9:bf0cf5828378 | 188 | // copy over the dispatch |
ansond | 9:bf0cf5828378 | 189 | memset(buffer,0,buffer_length); |
ansond | 9:bf0cf5828378 | 190 | int length = this->m_recv_raw_data_length; |
ansond | 9:bf0cf5828378 | 191 | if (length > buffer_length) { |
ansond | 9:bf0cf5828378 | 192 | 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 | 193 | length = buffer_length; |
ansond | 9:bf0cf5828378 | 194 | } |
ansond | 9:bf0cf5828378 | 195 | memcpy(buffer,this->m_recv_raw_data,length); |
ansond | 9:bf0cf5828378 | 196 | |
ansond | 9:bf0cf5828378 | 197 | // now reset |
ansond | 9:bf0cf5828378 | 198 | this->resetLocalDispatch(); |
ansond | 9:bf0cf5828378 | 199 | |
ansond | 9:bf0cf5828378 | 200 | // return the length |
ansond | 9:bf0cf5828378 | 201 | return length; |
ansond | 9:bf0cf5828378 | 202 | } |
ansond | 9:bf0cf5828378 | 203 | return 0; |
ansond | 9:bf0cf5828378 | 204 | } |
ansond | 9:bf0cf5828378 | 205 | |
ansond | 9:bf0cf5828378 | 206 | // accumulate to dispatch locally... |
ansond | 35:71eb3663ecbd | 207 | bool UartRPC::accumulate(uint8_t *buffer,int buffer_length) { |
ansond | 35:71eb3663ecbd | 208 | //DBG("UartRPC:: accumulating... [%s] length=%d bytes...\r\n",buffer,buffer_length); |
ansond | 35:71eb3663ecbd | 209 | |
ansond | 9:bf0cf5828378 | 210 | // add to the accumulator |
ansond | 9:bf0cf5828378 | 211 | this->m_recv_accumulator.add(buffer,buffer_length); |
ansond | 9:bf0cf5828378 | 212 | |
ansond | 9:bf0cf5828378 | 213 | // determine if we have a completed packet by looking for the "tail" |
ansond | 9:bf0cf5828378 | 214 | return this->m_recv_accumulator.hasCollectedCharacter(']'); |
ansond | 5:9233e88b9c83 | 215 | } |