├── LICENSE ├── README.md ├── vector-BLE ├── CLAD.cpp ├── OS-X │ ├── Vector-BLE.h │ └── Vector-BLE.m ├── README.md ├── Vector-req.cpp ├── link.cpp ├── utils.h └── vector-BLE.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── randym.xcuserdatad │ │ ├── IDEFindNavigatorScopes.plist │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── randym.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── Anki-1.xcscheme │ └── xcschememanagement.plist └── victor-ctrl /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Randall Maas 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vectors-cmdline-tools 2 | Tools to work with the Anki Vector robot 3 | -------------------------------------------------------------------------------- /vector-BLE/CLAD.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CLAD.cpp 3 | // Anki-1 4 | // 5 | // Created by Randall Maas on 10/3/19. 6 | // Copyright © 2019 Randall Maas. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include "utils.h" 13 | 14 | void CLAD_nextStep(); 15 | 16 | 17 | /** This is called to display a string embedded in nybbles 18 | @param str The nybbles 19 | @param len The number of bytes in the str buffer 20 | */ 21 | static void printHexString(uint8_t const* str, size_t len) 22 | { 23 | while (len > 0) 24 | { 25 | uint8_t c = ascii2hex(*str++); c<<=4; 26 | c|=ascii2hex(*str++); 27 | len-=2; 28 | fputc(c, stdout); 29 | } 30 | } 31 | 32 | 33 | /** This is called to display a string 34 | @param str The nybbles 35 | @param len The number of bytes in the str buffer 36 | */ 37 | static void printString(uint8_t const* str, size_t len) 38 | { 39 | fwrite(str, len, 1, stdout); 40 | } 41 | 42 | /** This is called to interpret the response message 43 | @param msg the received bytes of a message 44 | @param size the number of bytes in the message 45 | @param version the format version of the message 46 | */ 47 | void response_recv(uint8_t const* msg, size_t size, uint8_t version) 48 | { 49 | uint16_t code = LEU16_decode(msg); 50 | uint8_t len = msg[2]; 51 | printf("\nResponse"); 52 | printf("\n\tcode : %d", code); 53 | if (0 == code) 54 | printf(" not cloud authorized"); // otherwise authorized 55 | //printf("\n\tlen : %d", len); 56 | printf(" ["); 57 | fwrite(msg+3,1,len,stdout); 58 | printf("]\n\n"); 59 | fflush(stdout); 60 | } 61 | 62 | #pragma mark --- Status -------------------------------------------------------- 63 | /** This is called to interpret the stats message 64 | @param msg the received bytes of a message 65 | @param size the number of bytes in the message 66 | @param version the format version of the message 67 | 68 | This is the response to a status info request 69 | status_req() 70 | or 71 | sendMsg(0xa,0); 72 | */ 73 | void status_recv(uint8_t const* msg, size_t size, uint8_t version) 74 | { 75 | printf("\nStatus"); 76 | auto SSID_len = *msg++; 77 | printf("\n\tSSID : "); printHexString(msg,SSID_len); msg+= SSID_len; 78 | printf("\n\tWIFI state : %d", *msg++); 79 | printf("\n\taccess point : %d", *msg++); 80 | printf("\n\tBluetooth LE state: %d", *msg++); 81 | printf("\n\tBattery state : %d", *msg++); 82 | if (version >= 2) 83 | { 84 | auto ver_len = *msg++; 85 | printf("\n\tVersion : "); printString(msg,ver_len); msg+= ver_len; 86 | } 87 | if (version >= 4) 88 | { 89 | auto ESN_len = *msg++; 90 | printf("\n\tESN : "); printString(msg,ESN_len); msg+= ESN_len; 91 | } 92 | if (version >= 2) printf("\n\tOTA in progress : %d", *msg++); 93 | if (version >= 3) printf("\n\thas owner : %d", *msg++); 94 | if (version >= 5) printf("\n\tcloud authorized : %d", *msg++); 95 | 96 | printf("\n\n");fflush(stdout); 97 | } 98 | 99 | 100 | #pragma mark --- Log ---------------------------------------------------------- 101 | /// The file to store the log into 102 | FILE* logFile; 103 | 104 | /** This is called to interpret the file download message 105 | @param msg the received bytes of a message 106 | @param size the number of bytes in the message 107 | @param version the format version of the message 108 | 109 | This is the response to a log request 110 | log_req() 111 | or 112 | sendMsg(0x18,0); 113 | 114 | The file download will be a .tar.bz2, with contents like: 115 | data/diagnostics/logs/connman-services.txt 116 | data/diagnostics/logs/dmesg.txt 117 | data/diagnostics/logs/ifconfig.txt 118 | data/diagnostics/logs/iwconfig.txt 119 | data/diagnostics/logs/log.txt 120 | data/diagnostics/logs/netstat-ptlnu.txt 121 | data/diagnostics/logs/ping-anki.txt 122 | data/diagnostics/logs/ping-gateway.txt 123 | data/diagnostics/logs/ps.txt 124 | data/diagnostics/logs/top.txt 125 | data/boot.log 126 | factory/log0 127 | factory/log1 128 | run/update-engine/error 129 | 130 | These might differ based on the firmware version on Vector. 131 | 132 | These may be selectable by log filter 133 | */ 134 | void fileDownload_recv(uint8_t const* msg, size_t size, uint8_t version) 135 | { 136 | // Decode the fields 137 | uint8_t status = msg[0]; 138 | uint32_t fileId = LEU32_decode(msg+1); 139 | uint32_t pktNum = LEU32_decode(msg+5); 140 | // The total number of packets to be sent for this file download 141 | uint32_t pktTotal = LEU32_decode(msg+9); 142 | // The number of bytes to follow (can be 0) 143 | uint16_t length = LEU16_decode(msg+13); 144 | 145 | // Things that could be done 146 | // * look up the file pointer for the fileId 147 | // * check the packet number 148 | fwrite(msg+15, 1, length, logFile); 149 | 150 | // see if we're done 151 | if (pktNum == pktTotal) 152 | { 153 | fprintf(stdout, "log: file download complete.\n"); 154 | fflush(logFile); 155 | fclose(logFile); 156 | } 157 | } 158 | 159 | 160 | /** This is called to interpret the log response message 161 | @param msg the received bytes of a message 162 | @param size the number of bytes in the message 163 | @param version the format version of the message 164 | 165 | This is the response to a log request 166 | log_req() 167 | or 168 | sendMsg(0x18,0); 169 | */ 170 | void log_recv(uint8_t const* msg, size_t size, uint8_t version) 171 | { 172 | // Decode the fields 173 | uint8_t status = msg[0]; 174 | uint32_t fileId = LEU32_decode(msg+1); 175 | fprintf(stderr, "log: downloading file\n"); 176 | } 177 | 178 | 179 | #pragma mark --- WIFI ---------------------------------------------------------- 180 | /** This is called to interpret the Cloud Session response message 181 | @param msg the received bytes of a message 182 | @param size the number of bytes in the message 183 | @param version the format version of the message 184 | 185 | This is the response to a WiFi access point request 186 | CloudSession_req() 187 | */ 188 | void CloudSession_recv(uint8_t const* msg, size_t size, uint8_t version) 189 | { 190 | uint8_t success = msg[0]; 191 | uint16_t len = LEU16_decode(msg+1); 192 | // The GUID is held in the rest of the message 193 | uint8_t const* GUID = msg +3; 194 | } 195 | 196 | 197 | /** This is called to interpret the WIFI access point response message 198 | @param msg the received bytes of a message 199 | @param size the number of bytes in the message 200 | @param version the format version of the message 201 | 202 | This is the response to a WiFi access point request 203 | WiFi_AP_req() 204 | or 205 | sendMsg(0x13,0); 206 | */ 207 | void WiFi_AP_recv(uint8_t const* msg, size_t size, uint8_t version) 208 | { 209 | // Decode the fields 210 | // enabled 0 if the WiFi access point is disabled, otherwise enabled 211 | uint8_t enabled = msg[0]; 212 | 213 | // The number of bytes in the SSID string; may be 0 214 | uint8_t SSID_len = msg[1]; 215 | // The WiFI SSID, as a hex string (hex string) 216 | // uint8_t[SSID length] 217 | auto SSID_hex = msg+2; 218 | 219 | // The number of bytes in the password string; may be 0 220 | uint8_t Password_len= msg[1]; 221 | // The WiFI password string 222 | // uint8_t[Password length] 223 | auto Password_str = msg+2; 224 | 225 | // Print the info out 226 | printf("\nWIFI Access Point Mode"); 227 | printf("\n\nenabled : %s", enabled?"yes":"no"); 228 | printf("\n\tSSID : "); printHexString(SSID_hex,SSID_len); 229 | printf("\n\tpassword : "); printString (Password_str, Password_len); 230 | printf("\n\n");fflush(stdout); 231 | } 232 | 233 | 234 | #pragma mark --- OTA ----------------------------------------------------------- 235 | /** This is called to interpret the OTA update response message 236 | @param msg the received bytes of a message 237 | @param size the number of bytes in the message 238 | @param version the format version of the message 239 | 240 | These may be selectable by log filter 241 | */ 242 | void OTA_recv(uint8_t const* msg, size_t size, uint8_t version) 243 | { 244 | // Decode the fields 245 | uint8_t status = msg[0]; 246 | uint64_t current = LEU64_decode(msg+1);//  The number of bytes downloaded 247 | uint64_t expected = LEU64_decode(msg+8);// The number of bytes expected to be downloaded 248 | 249 | static char const* const statusMsgs[] = {"idle","unknown","in progress", 250 | "complete", "rebooting", "error"}; 251 | 252 | printf("OTA: (%llu of %llu downloaded): %s (%d) \n", current, expected, status<= 5?statusMsgs[status]:"unknown", status); 253 | 254 | // see if we're done 255 | // The update has completed the download when the current number of bytes 256 | // match the expected number of bytes. 257 | if (current == expected) 258 | { 259 | //fprintf(stdout, "OTA: file download complete.\n"); 260 | if (1 == status||5 == status) exit(0); 261 | } 262 | } 263 | 264 | 265 | 266 | #pragma mark --- CLAD interface ------------------------------------------------ 267 | /** This is called to interpret the disconnect message 268 | @param msg the received bytes of a message 269 | @param size the number of bytes in the message 270 | @param version the format version of the message 271 | */ 272 | void CLAD_disconnect(uint8_t const* msg, size_t size, uint8_t version) 273 | { 274 | (void) size; 275 | (void) msg; 276 | (void) version; 277 | fprintf(stderr, "Vector: link closed by Vector\n"); 278 | exit(0); 279 | } 280 | 281 | 282 | /** This is called to interpret message 283 | @param type the type of message received 284 | @param msg the received bytes of a message 285 | @param size the number of bytes in the message 286 | @param version the format version of the message 287 | */ 288 | void CLAD_interpret(uint8_t type, uint8_t const* msg, size_t size, uint8_t version) 289 | { 290 | switch(type) 291 | { 292 | case 0: 293 | fprintf(stderr, "Vector: error, disconnected\n"); 294 | exit(-1); 295 | break; 296 | case 0x0b: 297 | // Status info 298 | status_recv(msg, size, version); 299 | break; 300 | case 0x14: 301 | // WIFI access point response 302 | WiFi_AP_recv(msg,size,version); 303 | break; 304 | case 0x19: 305 | // log response 306 | log_recv(msg,size,version); 307 | break; 308 | case 0x1a: 309 | // file download 310 | fileDownload_recv(msg,size,version); 311 | break; 312 | case 0x1e: 313 | // cloud session 314 | CloudSession_recv(msg,size,version); 315 | break; 316 | case 0x21: 317 | // response 318 | response_recv(msg, size, version); 319 | break; 320 | case 0xf: 321 | // OTA 322 | OTA_recv(msg, size, version); 323 | default: 324 | break; 325 | } 326 | 327 | // Add a receive done to trigger the next stuff 328 | CLAD_nextStep(); 329 | } 330 | 331 | // This is called when the lower layers are ready 332 | void CLAD_ready() 333 | { 334 | // Send a request for status info 335 | status_req(); 336 | } 337 | 338 | static int _argc; 339 | static const char** _argv; 340 | static int _myState = 0; 341 | 342 | // This is called after something else was received so that I can send out a 343 | // further command line-triggered action 344 | void CLAD_nextStep() 345 | { 346 | //if (_myState) return; 347 | if (_argc == 3 && 0==strcasecmp(_argv[1], "ap")) 348 | { 349 | if (_myState ==1) 350 | { 351 | _myState = 2; 352 | // access point mode 353 | WiFi_AP_req(0==strcasecmp(_argv[2], "enable")?1:0); 354 | return; 355 | } 356 | if (_myState == 2) exit(0); 357 | _myState = 1; 358 | // Request a cloud session first 359 | CloudSession_req("2ky3cjcJPmmcjHWd9AQ9FZS", "lappy2000", "companion-app"); 360 | return ; 361 | } 362 | else if (_argc == 3 && 0==strcasecmp(_argv[1], "log")) 363 | { 364 | if (_myState ==1) return; 365 | _myState = 1; 366 | // download the logs 367 | // set the file name 368 | // file name = _argv[2] 369 | logFile = fopen(_argv[2],"w"); 370 | log_req(); 371 | } 372 | // see if we should trigger an OTA download 373 | else if (_argc == 3 && 0==strcasecmp(_argv[1], "ota")) 374 | { 375 | if (0 != _myState) return; 376 | _myState = 1; 377 | // download the logs 378 | OTA_req(_argv[2]); 379 | } 380 | else 381 | { 382 | exit(0); 383 | } 384 | // Todo: 385 | // see if we should try to enable SSH 386 | // WIFI ip address 387 | // WIFI scan 388 | // Other wifi management 389 | } 390 | 391 | /* Some of the commands that can be done 392 | "ap enable" to enable access point 393 | "log FILENAME" to retrieve the logs 394 | */ 395 | int main(int argc, const char * argv[]) 396 | { 397 | _argc = argc; 398 | _argv = argv; 399 | // Scan for Vector 400 | bleScan(); 401 | return 0; 402 | } 403 | -------------------------------------------------------------------------------- /vector-BLE/OS-X/Vector-BLE.h: -------------------------------------------------------------------------------- 1 | // 2 | // Vector-BLE.h 3 | // Anki-1 4 | // 5 | // Created by Randall Maas on 10/1/19. 6 | // Copyright © 2019 Randall Maas All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import 12 | 13 | @interface VectorProxy : NSObject 14 | { 15 | /// The bluetooth peripheral that we are wrapping 16 | CBPeripheral* volatile _peripheral; 17 | } 18 | /// The name of the device 19 | @property(readonly) NSString * deviceName; 20 | 21 | 22 | /// The bluetooth peripheral that we are wrapping 23 | @property(atomic) CBPeripheral* peripheral; 24 | 25 | 26 | /** Initialize the structure with the bluetooth device 27 | @param peripheral The Bluetooth peripheral we are to use 28 | @returns nil on error, othwerise the wrapper 29 | */ 30 | - (id)initWithPeripheral:(CBPeripheral*) peripheral; 31 | 32 | @end 33 | 34 | -------------------------------------------------------------------------------- /vector-BLE/OS-X/Vector-BLE.m: -------------------------------------------------------------------------------- 1 | // 2 | // Vector-BLE.m 3 | // Anki-1 4 | // 5 | // Created by Randall Maas on 10/1/19. 6 | // Copyright © 2019 Randall Maas. All rights reserved. 7 | // 8 | #import 9 | #import "Vector-BLE.h" 10 | 11 | VectorProxy* vectorProxy; 12 | // The characteristic to write to 13 | static CBCharacteristic* vectorWrite; 14 | 15 | @interface BLE:NSObject 16 | { 17 | // this is needed ; otherwise the peripheral disappears and the connection 18 | // is lost 19 | id thingy; 20 | } 21 | @end 22 | @implementation BLE 23 | #pragma mark - CBCentralManager delegate methods 24 | /** Invoked whenever the central manager's state is updated. 25 | */ 26 | - (void) centralManagerDidUpdateState:(CBCentralManager*) central 27 | { 28 | [central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"FEE3"]] 29 | options:nil]; 30 | } 31 | 32 | 33 | /** This is invoked when the central discovers a peripheral while scanning. 34 | */ 35 | - (void) centralManager:(CBCentralManager *) central 36 | didDiscoverPeripheral:(CBPeripheral *) aPeripheral 37 | advertisementData:(NSDictionary *) advertisementData 38 | RSSI:(NSNumber *) RSSI 39 | { 40 | if (thingy) return; 41 | thingy = aPeripheral; 42 | // Automatically connect with the peripheral 43 | [central connectPeripheral: aPeripheral 44 | options: nil]; 45 | } 46 | 47 | 48 | /** Invoked whenever a connection is succesfully created with the peripheral. 49 | Discover available services on the peripheral 50 | */ 51 | - (void) centralManager:(CBCentralManager *) central 52 | didConnectPeripheral:(CBPeripheral *) peripheral 53 | { 54 | vectorProxy = [[VectorProxy alloc] initWithPeripheral:peripheral]; 55 | } 56 | 57 | 58 | /** Invoked whenever an existing connection with the peripheral is torn down. 59 | Reset local variables 60 | */ 61 | - (void) centralManager:(CBCentralManager*) central 62 | didDisconnectPeripheral:(CBPeripheral* ) aPeripheral 63 | error:(NSError* ) Error 64 | { 65 | } 66 | 67 | 68 | /** Invoked whenever the central manager fails to create a connection with the peripheral. 69 | */ 70 | - (void) centralManager:(CBCentralManager *)central 71 | didFailToConnectPeripheral:(CBPeripheral *)aPeripheral 72 | error:(NSError*) error 73 | { 74 | NSLog(@"Fail to connect to peripheral: %@ with error = %@", aPeripheral, [error localizedDescription]); 75 | aPeripheral . delegate = nil; 76 | } 77 | @end 78 | 79 | @implementation VectorProxy 80 | 81 | 82 | /** Initialize the structure with the bluetooth device 83 | @param BPeripheral The Bluetooth peripheral we are to use 84 | @returns nil on error, othwerise the wrapper 85 | */ 86 | - (id)initWithPeripheral:(CBPeripheral*) BPeripheral 87 | { 88 | if (!(self=[self init])) 89 | return self; 90 | _peripheral = BPeripheral; 91 | self.peripheral.delegate = self; 92 | // Get the characteristics for the peripheral service 93 | // This will call peripheral:didDiscoverCharacteristicsForService:error: 94 | [self.peripheral discoverServices: @[[CBUUID UUIDWithString:@"FEE3"]]]; 95 | return self; 96 | } 97 | 98 | 99 | #pragma mark - CBPeripheral delegate methods 100 | /** Invoked upon completion of a -[discoverServices:] request. 101 | Discover available characteristics on interested services 102 | */ 103 | - (void) peripheral:(CBPeripheral *) aPeripheral 104 | didDiscoverServices:(NSError *) error 105 | { 106 | for (CBService* service in aPeripheral.services) 107 | { 108 | // Get the characteristics for the peripheral service 109 | // This will call peripheral:didDiscoverCharacteristicsForService:error: 110 | [aPeripheral discoverCharacteristics: @[[CBUUID UUIDWithString:@"7D2A4BDA-D29B-4152-B725-2491478C5CD7"], 111 | [CBUUID UUIDWithString:@"30619F2D-0F54-41BD-A65A-7588D8C85B45"]] 112 | forService: service]; 113 | } 114 | } 115 | 116 | /* 117 | Invoked upon completion of a -[discoverCharacteristics:forService:] request. 118 | Perform appropriate operations on interested characteristics 119 | */ 120 | - (void) peripheral:(CBPeripheral *)aPeripheral 121 | didDiscoverCharacteristicsForService:(CBService *)service 122 | error:(NSError *)error 123 | { 124 | CBCharacteristic* recv=nil; 125 | for (CBCharacteristic *aChar in service.characteristics) 126 | { 127 | if ([aChar.UUID isEqual:[CBUUID UUIDWithString:@"7D2A4BDA-D29B-4152-B725-2491478C5CD7"]]) 128 | { 129 | vectorWrite = aChar; 130 | } 131 | else if ([aChar.UUID isEqual:[CBUUID UUIDWithString:@"30619F2D-0F54-41BD-A65A-7588D8C85B45"]]) 132 | { 133 | recv = aChar; 134 | } 135 | } 136 | [self.peripheral setNotifyValue:YES 137 | forCharacteristic:recv]; 138 | } 139 | 140 | 141 | #pragma mark - 142 | #pragma mark Characteristics interaction 143 | 144 | - (void) peripheral:(CBPeripheral *) aPeripheral 145 | didWriteValueForCharacteristic:(CBCharacteristic *) characteristic 146 | error:(NSError *) error 147 | { 148 | if (error) 149 | { 150 | NSLog(@"%s: %@: error %@", __FUNCTION__, characteristic.UUID, error); 151 | return; 152 | } 153 | } 154 | 155 | 156 | 157 | /** This is invoked upon completion of a -[readValueForCharacteristic:] request or 158 | on the reception of a notification/indication. 159 | */ 160 | - (void) peripheral:(CBPeripheral *) aPeripheral 161 | didUpdateValueForCharacteristic:(CBCharacteristic *) characteristic 162 | error:(NSError *) error 163 | { 164 | void bleRecv(void const* bytes, size_t length); 165 | if (error) 166 | { 167 | NSLog(@"%s: %@: error %@", __FUNCTION__, characteristic.UUID, error); 168 | return; 169 | } 170 | bleRecv(characteristic.value.bytes,characteristic.value.length); 171 | } 172 | @end 173 | 174 | 175 | /** Writes a given value to the characteristics 176 | @param value The values to write 177 | */ 178 | 179 | /** This is called when the Bluetoth LE stack receives a charatristic 180 | @param bytes the received bytes 181 | @param length the number of bytes received 182 | */ 183 | void bleSend(void const* bytes, size_t length) 184 | { 185 | NSData* data = [NSData dataWithBytes: bytes 186 | length:length]; 187 | [vectorProxy.peripheral writeValue: data 188 | forCharacteristic: vectorWrite 189 | type: CBCharacteristicWriteWithResponse]; 190 | } 191 | 192 | 193 | /** This is called to start scanning for and conect to the first Vector it sees 194 | */ 195 | void bleScan() 196 | { 197 | static CBCentralManager* centralManager; 198 | static BLE* a; 199 | a = [[BLE alloc] init]; 200 | centralManager = [[CBCentralManager alloc] initWithDelegate: a 201 | queue:nil]; 202 | @autoreleasepool 203 | { 204 | [[NSRunLoop currentRunLoop] run]; 205 | } 206 | } 207 | 208 | -------------------------------------------------------------------------------- /vector-BLE/README.md: -------------------------------------------------------------------------------- 1 | # Vector Bluetooth LE reference implementation 2 | 3 | This is a demonstration of code that loves Vectors' Bluetooth 4 | The orginal repository is [https://github.com/randym32/Vectors-cmdline-tools](https://github.com/randym32/Vectors-cmdline-tools) 5 | 6 | ## Getting Started 7 | 8 | If you compile and run this, it will get the status from a vector. 9 | 1. Put Vector into pairing mode: put him on the charger, and double click his backpack button 10 | 2. Run the program 11 | 3. Enter the Pin code 12 | 13 | ## Further work 14 | 15 | The protocol is documented. Other commands could be implemented 16 | * Implement the command to direct the over-the-air update, and watch it status 17 | * The SSH authorization is interesting. It isn't clear if SSH is available on release firmware. I didn't see anything like a ssh server in the file system images 18 | * The SDK proxy is interesting. It would be nice to extend the regular Anki Vector SDK to allow this option 19 | 20 | The full protocol is documented in a write up called Vector-TRM.pdf 21 | 22 | ### Prerequisites 23 | 24 | You will need to install libsodium 25 | If you are running on a non-OS X /iOS operating system, you will have to write the Bluetooth LE specific interface. 26 | 27 | ## Deployment 28 | 29 | Add additional notes about how to deploy this on a live system 30 | 31 | ## Built With 32 | 33 | * [libsodium](https://libsodium.gitbook.io/doc/) 34 | 35 | ## Authors 36 | 37 | * **Randall Maas** 38 | 39 | ## License 40 | 41 | This project is licensed under the BSD 2-Clause License - see the [LICENSE.md](LICENSE.md) file for details 42 | -------------------------------------------------------------------------------- /vector-BLE/Vector-req.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CLAD-req.cpp 3 | // vector-BLE 4 | // 5 | // Created by Randall Maas on 11/2/19. 6 | // Copyright © 2019 Blackwood Designs, LLC. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include "utils.h" 12 | 13 | /** A helper to convert ASCII hex to binary 14 | @param c characte to convert 15 | @returns the converted value 16 | */ 17 | uint8_t ascii2hex(char c) 18 | { 19 | if (c >= '0' && c <= '9') return c-'0'; 20 | if (c >= 'a' && c <= 'f') return 10+(c-'a'); 21 | if (c >= 'A' && c <= 'F') return 10+(c-'A'); 22 | return 0; 23 | } 24 | 25 | #pragma mark --- Status -------------------------------------------------------- 26 | /** This is called to request status info from Vector 27 | */ 28 | void status_req(void) 29 | { 30 | // Send a request for status info 31 | sendMsg(0xa,0); 32 | } 33 | 34 | 35 | #pragma mark --- Log ---------------------------------------------------------- 36 | /** This is called to request a log from Vector 37 | 38 | The follow up should call log_resp() and fileDownload_recv() 39 | */ 40 | void log_req(void) 41 | { 42 | // mode (enumeration unknown) 43 | out_msg[0] = 0; 44 | 45 | // num filters 46 | LEU16_encode(out_msg, 0); 47 | 48 | // each filter 49 | // none for now 50 | 51 | // Send a request for log info 52 | sendMsg(0x18,3); 53 | } 54 | 55 | 56 | #pragma mark --- WIFI ---------------------------------------------------------- 57 | 58 | /** This is called to request a cloud session 59 | @param token The session token from the cloud service 60 | @param clientName The name of the computer[?] 61 | @param applicationId The name of the application software 62 | */ 63 | void CloudSession_req(char const* token, char const* clientName, char const* applicationId) 64 | { 65 | uint16_t len = strlen(token); 66 | LEU16_encode(out_msg, len); 67 | uint16_t ofs = 2; 68 | memcpy(out_msg+ofs,token, len); 69 | ofs+= len; 70 | len = strlen(clientName); 71 | out_msg[ofs] = len; 72 | ofs++; 73 | memcpy(out_msg+ofs,clientName, len); 74 | ofs+= len; 75 | len = strlen(applicationId); 76 | out_msg[ofs] = len; 77 | ofs++; 78 | memcpy(out_msg+ofs,applicationId, len); 79 | ofs+= len; 80 | 81 | // Send a request for Cloud session 82 | sendMsg(0x1d,ofs); 83 | } 84 | 85 | 86 | /** This is called to request Vector become a WIFI access point 87 | @param enable 0 to disable the WIFI access point, otherwuse to enable the 88 | access point 89 | 90 | If not cloud authorized, this will give a response 0x21 (response message) 91 | with an error message that this is not cloud authorized. 92 | 93 | Under other conditions (TBD) an "access point" response will come back and 94 | explain what is going on 95 | 96 | The hypothesis is that enabling the WIFI access point will enable a UDP 97 | server on Vector that is similar to the one on Cozmo; the pycozmo figured 98 | much of Cozmo's protocol. 99 | */ 100 | void WiFi_AP_req(uint8_t enable) 101 | { 102 | // enable / disable the WIFI access point 103 | out_msg[0] = enable?1:0; 104 | 105 | // Send a request for WiFI Access point 106 | sendMsg(0x13,1); 107 | } 108 | 109 | 110 | #pragma mark --- OTA ----------------------------------------------------------- 111 | 112 | /** This is called to request an Over The Air update 113 | @param URL The URL to download the firmware from 114 | */ 115 | void OTA_req(char const* URL) 116 | { 117 | uint8_t length = strlen(URL); 118 | out_msg[0] = length ; // The length of the URL 119 | memcpy(out_msg+1, URL, length); // The URL string 120 | // Send a request for an OTA update 121 | sendMsg(0xe, length+1); 122 | } 123 | -------------------------------------------------------------------------------- /vector-BLE/link.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // link.cpp 3 | // Anki-1 4 | // 5 | // Created by Randall Maas on 10/1/19. 6 | // Copyright © 2019 Randall Maas. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include "/usr/local/include/sodium.h" 12 | #include "utils.h" 13 | 14 | /// The version of the protocol and message formats 15 | int protoVersion; 16 | 17 | 18 | /// The maximum size of a message at the "CLAD" layer 19 | #define CLAD_MAX_SIZE (65536+1024) 20 | 21 | /// The maximum number of bytes that can be put into a BLE payload 22 | #define PAYLOAD_MAX_SIZE (19) 23 | 24 | /// The kind of frame 25 | enum 26 | { 27 | VBLE_continue= 0<<6, 28 | VBLE_end = 1<<6, 29 | VBLE_start = 2<<6, 30 | VBLE_solo = 3<<6 31 | }; 32 | 33 | /// A buffer to hold the outgoing message 34 | uint8_t out_buf[4+CLAD_MAX_SIZE]; 35 | 36 | /// A pointer into the payload area of the message 37 | uint8_t* out_msg=out_buf+3; 38 | 39 | 40 | #pragma mark credentials 41 | /// The credentials for communicating with vector 42 | uint8_t Vector_publicKey[crypto_kx_PUBLICKEYBYTES]; 43 | 44 | 45 | /** A place for the operator to enter the pin code 46 | @param pin A buffer to hold the pin code 47 | @param pinLen The size of the buffer 48 | This can be overridden by another module 49 | */ 50 | __attribute__((weak)) void UI_getPin(char* pin, int pinLen) 51 | { 52 | printf("enter pin: "); fflush(stdout); 53 | pin[0]=0; 54 | fgets(pin, pinLen, stdin); 55 | pin[pinLen]=0; 56 | // get rid of newline 57 | for (auto I = 0; I < pinLen && pin[I]; I++) 58 | if ('\n' == pin[I]) 59 | { 60 | pin[I] = 0; 61 | break; 62 | } 63 | } 64 | 65 | /// This is set once we are supposed to start using the encryption 66 | uint8_t useEncryption = 0; 67 | uint8_t publicKey [crypto_kx_PUBLICKEYBYTES]; 68 | uint8_t secretKey [crypto_kx_SECRETKEYBYTES]; 69 | uint8_t encryptionKey[crypto_kx_SESSIONKEYBYTES]; 70 | uint8_t encryptionNonce[24]; 71 | uint8_t decryptionKey[crypto_kx_SESSIONKEYBYTES]; 72 | uint8_t decryptionNonce[24]; 73 | 74 | 75 | 76 | 77 | 78 | #pragma mark Link related message processing 79 | 80 | /// This is use to track whether we've done the handshake yet 81 | static int didHandshake=0; 82 | 83 | 84 | /** This is called to interpret the connect-request message 85 | @param msg the received bytes of a message 86 | @param size the number of bytes in the message 87 | @param version the format version of the message 88 | */ 89 | static void connRequest_recv(uint8_t const* msg, size_t size, uint8_t version) 90 | { 91 | (void) size; 92 | // A connection message is a public key 93 | memcpy(Vector_publicKey, msg, 32); 94 | 95 | // first time vs other 96 | // Before running this program, you will have to press the button his back 97 | // twice, while he is on the charger 98 | crypto_kx_keypair(publicKey, secretKey); 99 | 100 | // create message 101 | out_msg[0] = 0; // first time 102 | memcpy(out_msg+1, publicKey, crypto_kx_PUBLICKEYBYTES); 103 | sendMsg(2, 1+crypto_kx_PUBLICKEYBYTES); 104 | 105 | // IF not the first time, can reuse the publicKey / etc rom the past 106 | } 107 | 108 | 109 | /** This is called to interpret the disconnect message 110 | @param msg the received bytes of a message 111 | @param size the number of bytes in the message 112 | @param version the format version of the message 113 | */ 114 | __attribute__((weak)) void CLAD_disconnect(uint8_t const* msg, size_t size, uint8_t version) 115 | { 116 | (void) size; 117 | (void) msg; 118 | (void) version; 119 | fprintf(stderr, "Vector: link closed by Vector\n"); 120 | } 121 | 122 | 123 | /** This is called to interpret the disconnect message 124 | @param msg the received bytes of a message 125 | @param size the number of bytes in the message 126 | @param version the format version of the message 127 | */ 128 | static void nonce_recv(uint8_t const* msg, size_t size, uint8_t version) 129 | { 130 | (void) size; 131 | (void) msg; 132 | (void) version; 133 | 134 | // Set up the nonces 135 | memcpy(encryptionNonce, msg , 24); // the to robot nonce 136 | memcpy(decryptionNonce, msg+24, 24); // the to application nonce 137 | 138 | // set up the session keys 139 | char pin[16]; 140 | UI_getPin(pin, sizeof(pin)-1); 141 | pin[sizeof(pin)-1]=0; 142 | 143 | (void) crypto_kx_client_session_keys(decryptionKey, encryptionKey, publicKey, secretKey, Vector_publicKey); 144 | size_t pin_length = strlen((char*)pin); 145 | crypto_generichash(encryptionKey, sizeof(encryptionKey), encryptionKey, sizeof(encryptionKey), (uint8_t*) pin, pin_length); 146 | crypto_generichash(decryptionKey, sizeof(decryptionKey), decryptionKey, sizeof(decryptionKey), (uint8_t*) pin, pin_length); 147 | 148 | // send an ack 149 | out_msg[0] = 3; // What does this mean? 150 | sendMsg(0x12, 1); 151 | // Now that we have the nonce, everything we do should use the encryption 152 | useEncryption = 1; 153 | } 154 | 155 | /** This is called to test the encryption by Vector 156 | @param msg the received bytes in the message 157 | @param size the number of bytes in the message 158 | @param msgVersion The format version the message was encoded in 159 | */ 160 | static void challenge_recv(uint8_t const* msg, size_t size, uint8_t msgVersion) 161 | { 162 | // get the challenge value 163 | uint32_t challenge = LEU32_decode(msg); 164 | // increment it and sent it back 165 | LEU32_encode(out_msg, challenge+1); 166 | sendMsg(4, 4); 167 | } 168 | 169 | 170 | /** This is called to interpret the challenge success message 171 | @param msg the received bytes of a message 172 | @param size the number of bytes in the message 173 | @param version the format version of the message 174 | */ 175 | static void success_recv(uint8_t const* msg, size_t size, uint8_t version) 176 | { 177 | (void) size; 178 | (void) msg; 179 | (void) version; 180 | // let the next leve know that we are ready 181 | CLAD_ready(); 182 | } 183 | 184 | #pragma mark receive, defragement decrypt 185 | 186 | /** This is called when the Bluetoth LE stack receives a charatristic 187 | @param frame the received bytes (a frame) 188 | @param length the number of bytes received 189 | */ 190 | void bleRecv(uint8_t const* frame, size_t length) 191 | { 192 | // Perform reassembly on the packet 193 | // This buffer should be big enough for the worst case 194 | static uint8_t _buffer[CLAD_MAX_SIZE]; 195 | auto buffer = _buffer; 196 | static off_t buf_ofs = 0; 197 | 198 | // get the number of bytes in the fragment 199 | // todo: sanity check the received bytes with the length embedded 200 | auto payloadSize = frame[0]&0x3f; 201 | 202 | // check to see how to reassemble 203 | switch(frame[0]&~0x3f) 204 | { 205 | case VBLE_start: 206 | case VBLE_solo: buf_ofs = 0; break; 207 | } 208 | 209 | // append the payload to the CLAD message buffer 210 | memcpy(buffer+buf_ofs,frame+1,payloadSize); 211 | buf_ofs += payloadSize; 212 | 213 | // see if there is more to do 214 | switch(frame[0]&~0x3f) 215 | { 216 | default: 217 | return; 218 | case VBLE_solo: 219 | case VBLE_end: 220 | // reassembly complete, pass onto next stage 221 | break; 222 | } 223 | 224 | // Have we done a handshake? 225 | if (!didHandshake) 226 | { 227 | // Process the bytes as a handshake, if we haven't done so already 228 | // decode versions and such 229 | didHandshake = 1; 230 | protoVersion = LEU32_decode(buffer+1); 231 | // send the bytes back 232 | bleSend(frame, length); 233 | return; 234 | } 235 | 236 | // check to see if we should decrypt it now 237 | uint8_t message[CLAD_MAX_SIZE]; 238 | if (useEncryption) 239 | { 240 | // decrypt 241 | unsigned long long destLen=0; 242 | (void) crypto_aead_xchacha20poly1305_ietf_decrypt(message, &destLen, NULL, buffer, buf_ofs, NULL, 0L, decryptionNonce, decryptionKey); 243 | 244 | // update the nonce 245 | sodium_increment(decryptionNonce, sizeof decryptionNonce); 246 | 247 | buffer = message; 248 | buf_ofs = destLen; 249 | } 250 | 251 | 252 | // The next part is a little tricky. 253 | // There are 1 to 2 bytes that indicte the message format version 254 | int msgVersion = 1; 255 | auto msgBody = buffer+1; 256 | auto msgSize = buf_ofs-1; 257 | // buffer[0] is either 1 or 4 258 | if (4 == buffer[0]) 259 | { 260 | // The message version is embedded 261 | msgVersion = *msgBody++; 262 | msgSize--; 263 | } 264 | 265 | // The next byte is the tag indicating type of message 266 | auto msgType = *msgBody++; 267 | msgSize --; 268 | 269 | // process the link-related messages 270 | switch(msgType) 271 | { 272 | case 1: 273 | // A connection message 274 | connRequest_recv(msgBody, msgSize, msgVersion); 275 | return; 276 | case 0x11: 277 | // A close connection 278 | CLAD_disconnect(msgBody, msgSize, msgVersion); 279 | return; 280 | case 3: 281 | // A nonce message 282 | nonce_recv(msgBody, msgSize, msgVersion); 283 | return; 284 | case 4: 285 | // A challenge message 286 | challenge_recv(msgBody, msgSize, msgVersion); 287 | return; 288 | case 5: 289 | // A challenge success 290 | success_recv(msgBody, msgSize, msgVersion); 291 | return; 292 | 293 | default: 294 | // pass control to the higher level processing 295 | CLAD_interpret(msgType, msgBody, msgSize, msgVersion); 296 | break; 297 | } 298 | } 299 | 300 | 301 | #pragma mark encrypt, fragement and send 302 | /** This is called to interpret message 303 | @param tag the message code 304 | @param size the number of bytes in the message 305 | */ 306 | void sendMsg(uint8_t tag, size_t size) 307 | { 308 | uint8_t _cipher[CLAD_MAX_SIZE]; 309 | // Fill in the version of protocol that we are using... 310 | out_buf[0]= 4; 311 | out_buf[1]= protoVersion; 312 | out_buf[2]= tag; 313 | 314 | uint8_t* cipher = out_buf; 315 | unsigned long long cipherLength = size+3; 316 | if (useEncryption) 317 | { 318 | // encrypt it 319 | crypto_aead_xchacha20poly1305_ietf_encrypt(_cipher, &cipherLength, out_buf, size+3, NULL, 0L, NULL, encryptionNonce, encryptionKey); 320 | cipher=_cipher; 321 | 322 | // update the nonce 323 | sodium_increment(encryptionNonce, sizeof encryptionNonce); 324 | } 325 | 326 | // fragment and send encrypted data 327 | int8_t buf[PAYLOAD_MAX_SIZE+1]; 328 | for (off_t ofs = 0; ofs < cipherLength;) 329 | { 330 | uint8_t messageType = VBLE_continue; 331 | auto payloadSize = cipherLength-ofs; 332 | if (0 == ofs) 333 | { 334 | messageType = (payloadSize <= PAYLOAD_MAX_SIZE) ? messageType = VBLE_solo: messageType = VBLE_start; 335 | } 336 | else if ((ofs+PAYLOAD_MAX_SIZE) >= cipherLength) 337 | { 338 | messageType = VBLE_end; 339 | } 340 | // clamp the patload size 341 | if (payloadSize > PAYLOAD_MAX_SIZE) 342 | { 343 | payloadSize = PAYLOAD_MAX_SIZE; 344 | } 345 | 346 | // put the frame together 347 | memcpy(buf+1,cipher+ofs, payloadSize); 348 | buf[0] = messageType | payloadSize; 349 | ofs += payloadSize; 350 | 351 | // pass it to the BLE stck 352 | bleSend(buf,payloadSize+1); 353 | } 354 | } 355 | 356 | 357 | -------------------------------------------------------------------------------- /vector-BLE/utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // utils.h 3 | // Anki-1 4 | // 5 | // Created by Randall Maas on 10/3/19. 6 | // Copyright © 2019 Randall Maas. All rights reserved. 7 | // 8 | 9 | #ifndef utils_h 10 | #define utils_h 11 | 12 | extern "C" 13 | { 14 | void bleScan(); 15 | void bleRecv(uint8_t const* bytes, size_t length); 16 | void bleSend(void const* bytes, size_t length); 17 | }; 18 | 19 | /// The version of the protocol and message formats 20 | extern int protoVersion; 21 | 22 | /// A pointer into the payload area of the message 23 | extern uint8_t* out_msg; 24 | 25 | /// This is used to map a 16-bit little endian to the native format 26 | #define LEU16_decode(p) (((p)[0] & 0xFFuL)| (((p)[1] << 8) & 0xFF00uL)) 27 | 28 | /// This is used to map a 32-bit little endian to the native format 29 | #define LEU32_decode(p) (LEU16_decode(p)|((uint32_t)LEU16_decode(p+2)<<16)) 30 | 31 | /// This is used to map a 32-bit little endian to the native format 32 | #define LEU64_decode(p) (LEU32_decode(p)|((uint64_t)LEU32_decode(p+4)<<32)) 33 | 34 | 35 | /** This is used to encode a 16-bit number into the little endian order 36 | @param buf The buffer to populate 37 | @param v The 16-bit value to place into the buffer 38 | 39 | Note: this is done by the explicit (tedious) method of populating the 40 | buffer instead of casting a pointer (e.g. *(uint16_t)*buf=v;) That approach 41 | bus faults on some architectures if the buffer isn't aligned just right. 42 | */ 43 | inline void LEU16_encode(void* buf, uint16_t v) 44 | { 45 | uint8_t* _buf = (uint8_t*) buf; 46 | *_buf++ = v&0xff; v>>=8; 47 | *_buf++ = v&0xff; v>>=8; 48 | } 49 | 50 | /** This is used to encode a 32-bit number into the little endian order 51 | @param buf The buffer to populate 52 | @param v The 32-bit value to place into the buffer 53 | 54 | Note: this is done by the explicit (tedious) method of populating the 55 | buffer instead of casting a pointer (e.g. *(uint32_t)*buf=v;) That approach 56 | bus faults on some architectures if the buffer isn't aligned just right. 57 | */ 58 | inline void LEU32_encode(void* buf, uint32_t v) 59 | { 60 | uint8_t* _buf = (uint8_t*) buf; 61 | *_buf++ = v&0xff; v>>=8; 62 | *_buf++ = v&0xff; v>>=8; 63 | *_buf++ = v&0xff; v>>=8; 64 | *_buf++ = v&0xff; v>>=8; 65 | } 66 | 67 | 68 | /** A helper to convert ASCII hex to binary 69 | @param c characte to convert 70 | @returns the converted value 71 | */ 72 | extern uint8_t ascii2hex(char c); 73 | 74 | 75 | /** This is called to interpret message 76 | @param tag the message code 77 | @param size the number of bytes in the message 78 | */ 79 | extern void sendMsg(uint8_t tag, size_t size); 80 | 81 | // This is called when the lower layers are ready 82 | extern void CLAD_ready(void); 83 | 84 | /** This is called to interpret message 85 | @param type the type of message received 86 | @param msg the received bytes of a message 87 | @param size the number of bytes in the message 88 | @param version the format version of the message 89 | */ 90 | extern void CLAD_interpret(uint8_t type, uint8_t const* msg, size_t size, uint8_t version); 91 | 92 | /** This is called to request status info from Vector 93 | */ 94 | extern void status_req(void); 95 | 96 | /** This is called to request a log from Vector 97 | 98 | The follow up should call log_resp() and fileDownload_recv() 99 | */ 100 | extern void log_req(void); 101 | 102 | /** This is called to request a cloud session 103 | @param token The session token from the cloud service 104 | @param clientName The name of the computer[?] 105 | @param applicationId The name of the application software 106 | */ 107 | extern void CloudSession_req(char const* token, char const* clientName, char const* applicationId); 108 | 109 | 110 | /** This is called to request Vector become a WIFI access point 111 | @param enable 0 to disable the WIFI access point, otherwuse to enable the 112 | access point 113 | 114 | If not cloud authorized, this will give a response 0x21 (response message) 115 | with an error message that this is not cloud authorized. 116 | 117 | Under other conditions (TBD) an "access point" response will come back and 118 | explain what is going on 119 | 120 | The hypothesis is that enabling the WIFI access point will enable a UDP 121 | server on Vector that is similar to the one on Cozmo; the pycozmo figured 122 | much of Cozmo's protocol. 123 | */ 124 | extern void WiFi_AP_req(uint8_t enable); 125 | 126 | /** This is called to request an Over The Air update 127 | @param URL The URL to download the firmware from 128 | */ 129 | extern void OTA_req(char const* URL); 130 | 131 | #endif /* utils_h */ 132 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3D03C317236DE44C00A7332A /* Vector-req.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D03C315236DE44C00A7332A /* Vector-req.cpp */; }; 11 | 3D54D88A2344243900275498 /* link.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D54D8892344243900275498 /* link.cpp */; }; 12 | 3D54D89B2344299D00275498 /* Vector-BLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D54D8992344299D00275498 /* Vector-BLE.m */; }; 13 | 3D5EE2142345F6A4009C7450 /* CLAD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D5EE2132345F6A4009C7450 /* CLAD.cpp */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | 3D54D8842344243900275498 /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = /usr/share/man/man1/; 21 | dstSubfolderSpec = 0; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 1; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 3D03C315236DE44C00A7332A /* Vector-req.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Vector-req.cpp"; sourceTree = ""; }; 30 | 3D54D8862344243900275498 /* vector-BLE */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "vector-BLE"; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 3D54D8892344243900275498 /* link.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = link.cpp; sourceTree = ""; }; 32 | 3D54D8982344299C00275498 /* Vector-BLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Vector-BLE.h"; sourceTree = ""; }; 33 | 3D54D8992344299D00275498 /* Vector-BLE.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Vector-BLE.m"; sourceTree = ""; }; 34 | 3D5EE2132345F6A4009C7450 /* CLAD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLAD.cpp; sourceTree = ""; }; 35 | 3D5EE21523460E50009C7450 /* utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | 3D54D8832344243900275498 /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 3D3172932345933F00772FE1 /* Frameworks */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | ); 53 | name = Frameworks; 54 | sourceTree = ""; 55 | }; 56 | 3D54D87D2344243900275498 = { 57 | isa = PBXGroup; 58 | children = ( 59 | 3D54D8892344243900275498 /* link.cpp */, 60 | 3D5EE21523460E50009C7450 /* utils.h */, 61 | 3D5EE2132345F6A4009C7450 /* CLAD.cpp */, 62 | 3D03C315236DE44C00A7332A /* Vector-req.cpp */, 63 | 3D54D8962344296F00275498 /* OS-X */, 64 | 3D54D8872344243900275498 /* Products */, 65 | 3D3172932345933F00772FE1 /* Frameworks */, 66 | ); 67 | sourceTree = ""; 68 | }; 69 | 3D54D8872344243900275498 /* Products */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 3D54D8862344243900275498 /* vector-BLE */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | 3D54D8962344296F00275498 /* OS-X */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 3D54D8982344299C00275498 /* Vector-BLE.h */, 81 | 3D54D8992344299D00275498 /* Vector-BLE.m */, 82 | ); 83 | path = "OS-X"; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXNativeTarget section */ 89 | 3D54D8852344243900275498 /* vector-BLE */ = { 90 | isa = PBXNativeTarget; 91 | buildConfigurationList = 3D54D88D2344243900275498 /* Build configuration list for PBXNativeTarget "vector-BLE" */; 92 | buildPhases = ( 93 | 3D54D8822344243900275498 /* Sources */, 94 | 3D54D8832344243900275498 /* Frameworks */, 95 | 3D54D8842344243900275498 /* CopyFiles */, 96 | ); 97 | buildRules = ( 98 | ); 99 | dependencies = ( 100 | ); 101 | name = "vector-BLE"; 102 | productName = "Anki-1"; 103 | productReference = 3D54D8862344243900275498 /* vector-BLE */; 104 | productType = "com.apple.product-type.tool"; 105 | }; 106 | /* End PBXNativeTarget section */ 107 | 108 | /* Begin PBXProject section */ 109 | 3D54D87E2344243900275498 /* Project object */ = { 110 | isa = PBXProject; 111 | attributes = { 112 | LastUpgradeCheck = 0920; 113 | ORGANIZATIONNAME = "Blackwood Designs, LLC"; 114 | TargetAttributes = { 115 | 3D54D8852344243900275498 = { 116 | CreatedOnToolsVersion = 9.2; 117 | ProvisioningStyle = Automatic; 118 | }; 119 | }; 120 | }; 121 | buildConfigurationList = 3D54D8812344243900275498 /* Build configuration list for PBXProject "vector-BLE" */; 122 | compatibilityVersion = "Xcode 8.0"; 123 | developmentRegion = en; 124 | hasScannedForEncodings = 0; 125 | knownRegions = ( 126 | en, 127 | ); 128 | mainGroup = 3D54D87D2344243900275498; 129 | productRefGroup = 3D54D8872344243900275498 /* Products */; 130 | projectDirPath = ""; 131 | projectRoot = ""; 132 | targets = ( 133 | 3D54D8852344243900275498 /* vector-BLE */, 134 | ); 135 | }; 136 | /* End PBXProject section */ 137 | 138 | /* Begin PBXSourcesBuildPhase section */ 139 | 3D54D8822344243900275498 /* Sources */ = { 140 | isa = PBXSourcesBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 3D5EE2142345F6A4009C7450 /* CLAD.cpp in Sources */, 144 | 3D54D89B2344299D00275498 /* Vector-BLE.m in Sources */, 145 | 3D03C317236DE44C00A7332A /* Vector-req.cpp in Sources */, 146 | 3D54D88A2344243900275498 /* link.cpp in Sources */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | /* End PBXSourcesBuildPhase section */ 151 | 152 | /* Begin XCBuildConfiguration section */ 153 | 3D54D88B2344243900275498 /* Debug */ = { 154 | isa = XCBuildConfiguration; 155 | buildSettings = { 156 | ALWAYS_SEARCH_USER_PATHS = NO; 157 | CLANG_ANALYZER_NONNULL = YES; 158 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 159 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 160 | CLANG_CXX_LIBRARY = "libc++"; 161 | CLANG_ENABLE_MODULES = YES; 162 | CLANG_ENABLE_OBJC_ARC = YES; 163 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 164 | CLANG_WARN_BOOL_CONVERSION = YES; 165 | CLANG_WARN_COMMA = YES; 166 | CLANG_WARN_CONSTANT_CONVERSION = YES; 167 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 168 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 169 | CLANG_WARN_EMPTY_BODY = YES; 170 | CLANG_WARN_ENUM_CONVERSION = YES; 171 | CLANG_WARN_INFINITE_RECURSION = YES; 172 | CLANG_WARN_INT_CONVERSION = YES; 173 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 174 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 175 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 176 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 177 | CLANG_WARN_STRICT_PROTOTYPES = YES; 178 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 179 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 180 | CLANG_WARN_UNREACHABLE_CODE = YES; 181 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 182 | CODE_SIGN_IDENTITY = "Mac Developer"; 183 | COPY_PHASE_STRIP = NO; 184 | DEBUG_INFORMATION_FORMAT = dwarf; 185 | ENABLE_STRICT_OBJC_MSGSEND = YES; 186 | ENABLE_TESTABILITY = YES; 187 | GCC_C_LANGUAGE_STANDARD = gnu11; 188 | GCC_DYNAMIC_NO_PIC = NO; 189 | GCC_NO_COMMON_BLOCKS = YES; 190 | GCC_OPTIMIZATION_LEVEL = 0; 191 | GCC_PREPROCESSOR_DEFINITIONS = ( 192 | "DEBUG=1", 193 | "$(inherited)", 194 | ); 195 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 196 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 197 | GCC_WARN_UNDECLARED_SELECTOR = YES; 198 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 199 | GCC_WARN_UNUSED_FUNCTION = YES; 200 | GCC_WARN_UNUSED_VARIABLE = YES; 201 | MACOSX_DEPLOYMENT_TARGET = 10.12; 202 | MTL_ENABLE_DEBUG_INFO = YES; 203 | ONLY_ACTIVE_ARCH = YES; 204 | SDKROOT = macosx; 205 | }; 206 | name = Debug; 207 | }; 208 | 3D54D88C2344243900275498 /* Release */ = { 209 | isa = XCBuildConfiguration; 210 | buildSettings = { 211 | ALWAYS_SEARCH_USER_PATHS = NO; 212 | CLANG_ANALYZER_NONNULL = YES; 213 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 215 | CLANG_CXX_LIBRARY = "libc++"; 216 | CLANG_ENABLE_MODULES = YES; 217 | CLANG_ENABLE_OBJC_ARC = YES; 218 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 219 | CLANG_WARN_BOOL_CONVERSION = YES; 220 | CLANG_WARN_COMMA = YES; 221 | CLANG_WARN_CONSTANT_CONVERSION = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 224 | CLANG_WARN_EMPTY_BODY = YES; 225 | CLANG_WARN_ENUM_CONVERSION = YES; 226 | CLANG_WARN_INFINITE_RECURSION = YES; 227 | CLANG_WARN_INT_CONVERSION = YES; 228 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 231 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 232 | CLANG_WARN_STRICT_PROTOTYPES = YES; 233 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 234 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 235 | CLANG_WARN_UNREACHABLE_CODE = YES; 236 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 237 | CODE_SIGN_IDENTITY = "Mac Developer"; 238 | COPY_PHASE_STRIP = NO; 239 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 240 | ENABLE_NS_ASSERTIONS = NO; 241 | ENABLE_STRICT_OBJC_MSGSEND = YES; 242 | GCC_C_LANGUAGE_STANDARD = gnu11; 243 | GCC_NO_COMMON_BLOCKS = YES; 244 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 245 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 246 | GCC_WARN_UNDECLARED_SELECTOR = YES; 247 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 248 | GCC_WARN_UNUSED_FUNCTION = YES; 249 | GCC_WARN_UNUSED_VARIABLE = YES; 250 | MACOSX_DEPLOYMENT_TARGET = 10.12; 251 | MTL_ENABLE_DEBUG_INFO = NO; 252 | SDKROOT = macosx; 253 | }; 254 | name = Release; 255 | }; 256 | 3D54D88E2344243900275498 /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | CODE_SIGN_STYLE = Automatic; 260 | DEVELOPMENT_TEAM = A4NK59Z4LE; 261 | LD_RUNPATH_SEARCH_PATHS = ""; 262 | LIBRARY_SEARCH_PATHS = /usr/local/lib; 263 | OTHER_LDFLAGS = ( 264 | "-lsodium", 265 | "-v", 266 | ); 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | }; 269 | name = Debug; 270 | }; 271 | 3D54D88F2344243900275498 /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | CODE_SIGN_STYLE = Automatic; 275 | DEVELOPMENT_TEAM = A4NK59Z4LE; 276 | LD_RUNPATH_SEARCH_PATHS = ""; 277 | LIBRARY_SEARCH_PATHS = /usr/local/lib; 278 | PRODUCT_NAME = "$(TARGET_NAME)"; 279 | }; 280 | name = Release; 281 | }; 282 | /* End XCBuildConfiguration section */ 283 | 284 | /* Begin XCConfigurationList section */ 285 | 3D54D8812344243900275498 /* Build configuration list for PBXProject "vector-BLE" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | 3D54D88B2344243900275498 /* Debug */, 289 | 3D54D88C2344243900275498 /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | 3D54D88D2344243900275498 /* Build configuration list for PBXNativeTarget "vector-BLE" */ = { 295 | isa = XCConfigurationList; 296 | buildConfigurations = ( 297 | 3D54D88E2344243900275498 /* Debug */, 298 | 3D54D88F2344243900275498 /* Release */, 299 | ); 300 | defaultConfigurationIsVisible = 0; 301 | defaultConfigurationName = Release; 302 | }; 303 | /* End XCConfigurationList section */ 304 | }; 305 | rootObject = 3D54D87E2344243900275498 /* Project object */; 306 | } 307 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/project.xcworkspace/xcuserdata/randym.xcuserdatad/IDEFindNavigatorScopes.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/project.xcworkspace/xcuserdata/randym.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/randym32/Vector-cmdline-tools/c37336765abad99cb96108eaf3c592397bfa5200/vector-BLE/vector-BLE.xcodeproj/project.xcworkspace/xcuserdata/randym.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/xcuserdata/randym.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 50 | 51 | 52 | 54 | 66 | 67 | 68 | 70 | 82 | 83 | 84 | 86 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/xcuserdata/randym.xcuserdatad/xcschemes/Anki-1.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 70 | 71 | 74 | 75 | 78 | 79 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /vector-BLE/vector-BLE.xcodeproj/xcuserdata/randym.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Anki-1.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3D54D8852344243900275498 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /victor-ctrl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # =================================================================== 4 | # This script creates the neccesary GUID 5 | # and performs an authorization with Vector 6 | # the first time it's executed or on demand by command switch. 7 | # 8 | # To request a new token for the GUID, 9 | # effectively renewing the authorization, 10 | # delete the file "json.blob" and run again 11 | # or use the menu item -reauth . 12 | #---------------------------------------------| 13 | # Parameter block 14 | # 15 | # api_key: 16 | anki_api_key=luyain9ep5phahP8aph8xa 17 | #---------------------------------------------| 18 | # 19 | # ANKI account and Vector IP 20 | # formatted as template below: 21 | #---------------------------------------------| 22 | # username=someone.somewhere@maildomain.dom 23 | # password=AbC123dEf 24 | # 25 | # vector_ip=192.168.1.123 26 | #---------------------------------------------| 27 | username=victor.robot@mail.dom 28 | password=xnxnxnxnxnxnx 29 | # 30 | vector_ip=10.0.13.37 31 | # 32 | # Logfile location: 33 | logfile=session.log 34 | # 35 | # Debug stuff: 36 | debug= 37 | if test "$debug" = "true" 38 | then 39 | proxystring="-kpx127.0.0.1:8080" 40 | else 41 | proxystring="" 42 | fi 43 | echo $debug 44 | echo $proxystring 45 | #---------------------------------------------| 46 | # 47 | # End of user parameter block 48 | #---------------------------------------------/ 49 | # 50 | # 51 | #---------------------------------------------\ 52 | # Let's do it: 53 | # Open logfile and provide some feedback: 54 | # 55 | echo >> $logfile 56 | echo "anki app key : "$anki_api_key >> $logfile 57 | echo "user name : "$username >> $logfile 58 | echo "password : "$password >> $logfile 59 | echo "vector ip : "$vector_ip >> $logfile 60 | echo 61 | # =================================================================== 62 | 63 | 64 | # =================================================================== 65 | # Fancy Banner 66 | # =================================================================== 67 | readonly prog_name="Victor*nixCTRL" 68 | readonly version="0.1 Persistent Alpha" 69 | readonly signature="Written 2019 by C0RE" 70 | readonly git_url="http://cyberspace/~c0re/vector" 71 | readonly bug_report_url="Please report bugs to ." 72 | 73 | # Colors for terminal output (b = bold) 74 | export red=$'\e[0;91m' 75 | export green=$'\e[0;92m' 76 | export blue=$'\e[0;94m' 77 | export white=$'\e[0;97m' 78 | export cyan=$'\e[0;96m' 79 | export endc=$'\e[0m' 80 | 81 | export bgreen=$'\e[1;92m' 82 | export bblue=$'\e[1;94m' 83 | export bwhite=$'\e[1;97m' 84 | export bcyan=$'\e[1;96m' 85 | export byellow=$'\e[1;96m' 86 | 87 | 88 | banner() { 89 | printf "${bblue} 90 | _ _ _ ___ _____ __ __ 91 | /\ /\(_) ___ | |_ ___ _ __ __/\__ _ __ (_)__ __ / __\/__ \ /__\ / / 92 | \ \ / /| | / __|| __|/ _ \ | '__|\ /| '_ \ | |\ \/ / / / / /\// \// / / 93 | \ V / | || (__ | |_| (_) || | /_ _\| | | || | > < / /___ / / / _ \/ /___ 94 | \_/ |_| \___| \__|\___/ |_| \/ |_| |_||_|/_/\_\ \____/ \/ \/ \_/\____/ 95 | V:$version 96 | 97 | =[ *NIX Swiss Army Knife for Victor Ver: $version 98 | =[ C0RE 99 | ${endc}\\n" 100 | } 101 | 102 | echo >> $logfile 103 | 104 | print_info(){ 105 | echo "anki app key : "$anki_api_key 106 | echo "user name : "$username 107 | echo "password : "$password 108 | echo "vector ip : "$vector_ip 109 | echo "logfile : "$logfile 110 | echo "proxy string : "$proxystring 111 | echo 112 | } 113 | 114 | #---------------------------------------------| 115 | # Initial token and auth stuff: 116 | # 117 | # Get session token and auth, skip if JSON blob file exist on disk: 118 | # 119 | if [ ! -f json.blob ]; then 120 | echo "JSON file not found, creating new." | tee -a $logfile && \ 121 | session=$( curl "$proxystring" -sH 'Anki-App-Key: '$anki_api_key'' --data "username=$username&password=$password" --compressed \ 122 | 'https://accounts.api.anki.com/1/sessions' ) 123 | echo $session > json.blob | tee -a $logfile 124 | 125 | # read JSON to session variable 126 | session=$( cat $"json.blob") 127 | session_token=$( echo $session | sed -n 's|.*"session_token":"\([^"]*\)".*|\1|p' ) 128 | echo "extracted session token: "$session_token | tee -a $logfile 129 | echo 130 | base64_session_token=$( echo -n $session_token | base64 ) 131 | echo "base64 encoded session token: "$base64_session_token | tee -a $logfile 132 | echo 133 | 134 | # Get client token guid: 135 | client_token_guid_JSON=$( curl -sH 'Accept: /' --data '{"user_session_id": "'$base64_session_token'"}' --compressed 'https://'$vector_ip'/v1/user_authentication' --insecure ) 136 | base64_client_token_guid=$( echo $client_token_guid_JSON | sed -n 's|.*"client_token_guid":"\([^"]*\)".*|\1|p' ) 137 | echo "extracted base64_client_token_guid: "$base64_client_token_guid | tee -a $logfile 138 | echo 139 | client_token_guid=$( echo -n $base64_client_token_guid | base64 -di) 140 | echo "base64 decoded client token guid: "$client_token_guid | tee -a $logfile 141 | echo 142 | echo $client_token_guid > client.guid 143 | client_token_guid=$( cat client.guid ) 144 | 145 | # Authorization: 146 | curl "$proxystring" -sH "Authorization: Bearer '$client_token_guid'" --data '{"jdoc_types": [0, 1, 2, 3]}' --compressed 'https://'$vector_ip'/v1/pull_jdocs' --insecure 147 | fi 148 | 149 | 150 | # End of initial token and auth stuff 151 | #---------------------------------------------/ 152 | 153 | #---------------------------------------------\ 154 | # Load saved client GUID from file: 155 | client_token_guid=$( cat client.guid ) 156 | #---------------------------------------------/ 157 | 158 | #---------------------------------------------\ 159 | # curl'ed endpoint requests: 160 | # 161 | # Request control: 162 | request_control() { 163 | curl -H 'Authorization: Bearer '$client_token_guid'' --request POST \ 164 | --data '{"control_request": {"priority": 20} }' --compressed 'https://'$vector_ip'/v1/assume_behavior_control' --insecure 165 | } 166 | 167 | # Request hi-priority control: 168 | request_control_hi() { 169 | curl -H 'Authorization: Bearer '$client_token_guid'' --request POST \ 170 | --data '{"control_request": {"priority": 10} }' --compressed 'https://'$vector_ip'/v1/assume_behavior_control' --insecure 171 | } 172 | 173 | # Release control: 174 | release_control() { 175 | curl -H 'Authorization: Bearer '$client_token_guid'' --request POST \ 176 | --data '{"control_release": {"priority": 20} }' --compressed 'https://'$vector_ip'/v1/assume_behavior_control' --insecure 177 | } 178 | 179 | # AlexaOptIn: 180 | alexa_optin() { 181 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 182 | --data '{"opt_in": true}' --compressed 'https://'$vector_ip'/v1/alexa_opt_in' --insecure 183 | } 184 | 185 | # Check Alexa State (JSON can be empty) 186 | alexa_check() { 187 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 188 | --data '{"alexa_auth_state": true}' --compressed 'https://'$vector_ip'/v1/alexa_auth_state' --insecure 189 | } 190 | 191 | # Drive off charger 192 | drive_off_charger() { 193 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 194 | --data '{"drive_off_charger": true}' --compressed 'https://'$vector_ip'/v1/drive_off_charger' --insecure 195 | } 196 | 197 | # Drive on charger 198 | drive_on_charger() { 199 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 200 | --data '{"drive_on_charger": true}' --compressed 'https://'$vector_ip'/v1/drive_on_charger' --insecure 201 | } 202 | 203 | # Look around in place: 204 | look_around() { 205 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 206 | --data '{"look_around": true}' --compressed 'https://'$vector_ip'/v1/look_around_in_place' --insecure 207 | } 208 | 209 | dock_cube() { 210 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 211 | --data '{"roll_block": true}' --compressed 'https://'$vector_ip'/v1/dock_with_cube' --insecure 212 | } 213 | 214 | # Roll cube: 215 | roll_block() { 216 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 217 | --data '{"roll_block": true}' --compressed 'https://'$vector_ip'/v1/roll_block' --insecure 218 | } 219 | 220 | # Get battery state: 221 | battery_state() { 222 | batt_blob=$( curl "$proxystring" -sH 'Authorization: Bearer '$client_guid'' --request POST \ 223 | --data '{"battery_state": true}' --compressed 'https://'$vector_ip'/v1/battery_state' --insecure ) 224 | if test "$debug" = "true" 225 | then 226 | echo $batt_blob | tee battery.blob 227 | fi 228 | batt_level=$( echo $batt_blob | sed -n 's|.*"battery_level":\([^"]*\),.*|\1|p' ) 229 | echo "Vector battery level : $batt_level" 230 | batt_volt=$( echo $batt_blob | sed -n 's|.*"battery_volts":\([^"]*\),"is_charging.*|\1|p' ) 231 | echo "Battery voltage : $batt_volt Volts" 232 | cube_id=$( echo $batt_blob | sed -n 's|.*"factory_id":"\([^"]*\)".*|\1|p' ) 233 | echo "Cube MAC : $cube_id" 234 | cube_level=$( echo $batt_blob | sed -n 's|.*"cube_battery":{"level":\([^"]*\),.*|\1|p' ) 235 | echo "Cube battery level : $cube_level" 236 | cube_volt=$( echo $batt_blob | sed -n 's|.*"e1:70:a0:ac:c4:c4","battery_volts":\([^"]*\),.*|\1|p' ) 237 | echo "Cube voltage : $cube_volt Volts." 238 | is_charging=$( echo $batt_blob | sed -n 's|.*"is_charging":\([^"]*\),.*|\1|p' ) 239 | echo "Vector is charging : $is_charging" 240 | is_on_charger=$( echo $batt_blob | sed -n 's|.*"is_on_charger_platform":\([^"]*\),.*|\1|p' ) 241 | echo "Vector is on charger : $is_on_charger" 242 | } 243 | 244 | 245 | # Snap photo: 246 | snap_pic() { 247 | json_pic_blob=$( curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' --request POST \ 248 | --data '{"capture_single_image": true}' --compressed 'https://'$vector_ip'/v1/capture_single_image' --insecure ) 249 | 250 | frame_time_stamp=$( echo $json_pic_blob | sed -n 's|.*"frame_time_stamp":\([^"]*\),.*|\1|p' ) 251 | base64_pic=$( echo $json_pic_blob | sed -n 's|.*"data":"\([^"]*\)".*|\1|p' ) 252 | echo -n $base64_pic | base64 -di > 'img_'$frame_time_stamp'.jpg' 253 | } 254 | 255 | # Get OTA update from ANKI 256 | get_ota() { 257 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' \ 258 | --data '{:}' --compressed 'https://'$vector_ip'/v1/update_and_restart' --insecure 259 | } 260 | # 261 | #---------------------------------------------/ 262 | proxy() { 263 | proxystring="-kpx127.0.0.1:8080" 264 | } 265 | 266 | # Say Text 267 | say_text() { 268 | curl "$proxystring" -H 'Authorization: Bearer '$client_token_guid'' --request POST \ 269 | --data '{"say_text": {"text": "Me is fed up with electrons, me want Pizza!","use_vector_voice": true,"duration_scalar": 1.0}}' --compressed 'https://'$vector_ip'/v1/say_text' --insecure 270 | } 271 | #---------------------------------------------/ 272 | 273 | # =================================================================== 274 | # Show help menù 275 | # =================================================================== 276 | usage() { 277 | printf "${green}%s${endc}\\n" "$prog_name $version" 278 | printf "${green}%s${endc}\\n" "Experimental Victor control tool for *NIX and Bash". 279 | printf "${green}%s${endc}\\n" "A simple tool to easily explore direct endpoint control of Vector." 280 | printf "${green}%s${endc}\\n" "This script only sends raw endpoint commands and arguments to the bot." 281 | printf "${green}%s${endc}\\n" "It doesn't handle any responses (yet) and probably shouldn't." 282 | printf "${green}%s${endc}\\n" "It was never my intention to create any companion-app substitute" 283 | printf "${green}%s${endc}\\n" "but to create a tool for my own exploration and hammering on endpoints." 284 | printf "${green}%s${endc}\\n" "For a thorough description of how to use it, see the README.txt" 285 | printf "${green}%s${endc}\\n\\n" "$signature" 286 | 287 | printf "${white}%s${endc}\\n\\n" "Schematic:" 288 | 289 | printf "${white}%s${endc} ${red}%s${endc} ${white}%s${endc} ${red}%s${endc}\\n" \ 290 | "┌─╼" "$USER" "╺─╸" "$(hostname)" 291 | printf "${white}%s${endc} ${green}%s${endc}\\n\\n" "└───╼" "$prog_name "╺─╸" (proxy) "╺─╸" [Victor API]" 292 | 293 | printf "${white}%s${endc}\\n\\n" "Options:" 294 | 295 | printf "${green}%s${endc}\\n" \ 296 | "-h, --help show this help message and exit" 297 | 298 | printf "${green}%s${endc}\\n" \ 299 | "-batt, --battery_state Get battery and charge status" 300 | 301 | printf "${green}%s${endc}\\n" \ 302 | "-reqc, --control_request Request control of Victor" 303 | 304 | printf "${green}%s${endc}\\n" \ 305 | "-reqchi, --control_request_hi Request hi priority control of Victor" 306 | 307 | printf "${green}%s${endc}\\n" \ 308 | "-relc, --control_release Release control of Victor" 309 | 310 | printf "${green}%s${endc}\\n" \ 311 | "-droffc, --drive_off_charger Drive off charger" 312 | 313 | printf "${green}%s${endc}\\n" \ 314 | "-dronc, --drive_on_charger Drive on charger" 315 | 316 | printf "${green}%s${endc}\\n" \ 317 | "-pic, --snap_single_image Snap a picture, download, decode and save to file" 318 | 319 | printf "${green}%s${endc}\\n" \ 320 | "-ota, --get_ota Request OTA and restart)" 321 | 322 | printf "${green}%s${endc}\\n" \ 323 | "-p, --proxy Use proxy for moniotring requests (must be the first switch)" 324 | 325 | printf "${green}%s${endc}\\n" \ 326 | "-i, --info Show parameter info" 327 | 328 | printf "${green}%s${endc}\\n" \ 329 | "-v, --version display program version and exit" 330 | 331 | printf "${green} 332 | Project URL: $git_url 333 | Report bugs: https://github.com/c0re/victor/issues${endc}\\n" 334 | exit 0 335 | } 336 | 337 | 338 | # =================================================================== 339 | # Main function 340 | # =================================================================== 341 | 342 | # Parse command line arguments and start program 343 | main() { 344 | if [[ "$#" -eq 0 ]]; then 345 | printf "%s\\n" "$prog_name: Argument required" 346 | printf "%s\\n" "Try '$prog_name --help' for more information." 347 | exit 1 348 | fi 349 | 350 | while [[ "$#" -gt 0 ]]; do 351 | case "$1" in 352 | -batt | --battery_state) 353 | battery_state 354 | ;; 355 | -reqc | --control_request) 356 | request_control 357 | ;; 358 | -reqchi | --control_request_hi) 359 | request_control_hi 360 | ;; 361 | -relc | --control_release) 362 | release_control 363 | ;; 364 | -droffc | --drive_off_charger) 365 | drive_off_charger 366 | ;; 367 | -dronc | --drive_on_charger) 368 | drive_on_charger 369 | ;; 370 | -look | --look_around) 371 | look_around 372 | ;; 373 | -dock | --dock_with_cube) 374 | dock_cube 375 | ;; 376 | -roll | --roll_block) 377 | roll_block 378 | ;; 379 | -pic | --capture_single_image) 380 | snap_pic 381 | ;; 382 | -say | --say_text) 383 | say_text 384 | ;; 385 | -ota | --get_ota) 386 | get_ota 387 | ;; 388 | -p | --proxy) 389 | proxy 390 | ;; 391 | -i | --info) 392 | banner 393 | print_info 394 | ;; 395 | -v | --version) 396 | banner 397 | print_version 398 | ;; 399 | -h | --help) 400 | banner 401 | usage 402 | exit 0 403 | ;; 404 | -- | -* | *) 405 | printf "%s\\n" "$prog_name: Invalid option '$1'" 406 | printf "%s\\n" "Try '$prog_name --help' for more information." 407 | exit 1 408 | ;; 409 | esac 410 | shift 411 | done 412 | } 413 | 414 | 415 | main "$@" 416 | 417 | --------------------------------------------------------------------------------