├── amdev ├── __init__.py └── amdev.py ├── data_parser ├── __init__.py └── input_parser.py ├── jni ├── Application.mk ├── Android.mk ├── sco.h ├── rfcomm.h ├── l2cap.h ├── hci_lib.h ├── bluetooth.h └── bluetooth.c ├── hcitool.h ├── .gitignore ├── fwupdate.h ├── README.md ├── default.conf ├── amlprocess.h ├── cmdparse.h ├── amchar.h ├── gapproto.h ├── amproto.h ├── common.h ├── LICENSE ├── amchar.c ├── amoldproto.c ├── amoldproto.h ├── amdev.h ├── amcmd.h ├── Makefile ├── .ycm_extra_conf.py ├── btio.h ├── fwupdate.c ├── gapproto.c ├── amproto.c ├── hcitool.c ├── cmdparse.c ├── att.h ├── main.c └── amidefs.h /amdev/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data_parser/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi armeabi-v7a 2 | -------------------------------------------------------------------------------- /hcitool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hcitool.h 3 | * 4 | * Created on: Sep 2, 2013 5 | * Author: dashesy 6 | */ 7 | 8 | #ifndef HCITOOL_H_ 9 | #define HCITOOL_H_ 10 | 11 | int do_lescan(); 12 | 13 | #endif /* HCITOOL_H_ */ 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | 3 | *.obj/ 4 | *.dir/ 5 | obj/ 6 | libs/ 7 | 8 | *.pyc 9 | *.npy 10 | *.pkl 11 | *.user 12 | *.old 13 | *.ncb 14 | *.suo 15 | *.aps 16 | *.DS_Store 17 | *.log 18 | 19 | *.*~ 20 | 21 | /amlink 22 | Debug/ 23 | Release/ 24 | .settings/ 25 | .metadata/ 26 | .idea/ 27 | .project 28 | .cproject 29 | .pydevproject 30 | -------------------------------------------------------------------------------- /fwupdate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link firmware update process 3 | * 4 | * @date March 10, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef FWUPDATE_H 10 | #define FWUPDATE_H 11 | 12 | int set_update_file(const char * szName); 13 | int process_fwstatus(amdev_t * dev, uint8_t * buf, ssize_t buflen); 14 | 15 | #endif // include guard 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # amiigo-link 2 | Amiigo offline utility. 3 | 4 | This utility is to completely control the device, set sampling and get **raw** data from Amiigo wristband and shoeclip devices. 5 | The processed data (biometrics, calories, steps, ...) will be available in a web SDK, please visit [Amiigo](http://www.amiigo.com) to read about new products and services and announcements. 6 | 7 | ## Usage 8 | Please use `amlink --help` for list of commands. 9 | -------------------------------------------------------------------------------- /default.conf: -------------------------------------------------------------------------------- 1 | # light sensors 2 | ls_fast_interval 300 3 | ls_slow_interval 300 4 | ls_sleep_interval 300 5 | ls_duration 30 6 | ls_duration_mul 1 7 | ls_debug 0 8 | # start new capture 9 | ls_flags 0xc0 10 | # to stop use 0x40 11 | # ls_flags 0x40 12 | ls_movement 250 13 | 14 | # accel rates 15 | accel_slow_rate 100 16 | accel_fast_rate 50 17 | accel_sleep_rate 1000 18 | 19 | # blinking 20 | blink_duration 15 21 | blink_led 6 22 | blink_speed 1 23 | 24 | -------------------------------------------------------------------------------- /amlprocess.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link data processing 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMLPROCESS_H 10 | #define AMLPROCESS_H 11 | 12 | #include "amdev.h" 13 | 14 | // Optional all-inclusive handles 15 | #define OPT_START_HANDLE 0x0001 16 | #define OPT_END_HANDLE 0xffff 17 | 18 | int discover_device(amdev_t * dev); 19 | int process_data(amdev_t * dev, uint8_t * buf, ssize_t buflen); 20 | void print_status(uint8_t status); 21 | 22 | #endif // include guard 23 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | ifneq ($(TARGET_SIMULATOR),true) 2 | 3 | LOCAL_PATH:= $(call my-dir)/../ 4 | 5 | include $(CLEAR_VARS) 6 | 7 | LOCAL_CFLAGS += -Wall 8 | 9 | LOCAL_LDLIBS := -L$(LOCAL_PATH)/lib -llog -g 10 | 11 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/include 12 | 13 | LOCAL_SRC_FILES:= main.c \ 14 | btio.c \ 15 | att.c \ 16 | hcitool.c \ 17 | 18 | # Taken from BlueZ 19 | LOCAL_SRC_FILES += jni/bluetooth.c\ 20 | jni/hci.c \ 21 | 22 | 23 | LOCAL_MODULE := amlink 24 | 25 | include $(BUILD_EXECUTABLE) 26 | 27 | endif # TARGET_SIMULATOR != true 28 | -------------------------------------------------------------------------------- /cmdparse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link command text parser 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef CMDPARSE_H 10 | #define CMDPARSE_H 11 | 12 | void cmd_init(void); 13 | 14 | int parse_file_exists(const char * szName); 15 | int parse_command(const char * szName); 16 | int parse_adapter(const char * szName); 17 | int parse_device(const char * szName); 18 | int parse_i2c_write(const char * szArg); 19 | int parse_i2c_read(const char * szArg); 20 | int parse_input_line(const char * szName) ; 21 | int parse_input_file(const char * szName) ; 22 | int parse_mode(const char * szName); 23 | 24 | 25 | #endif // include guard 26 | -------------------------------------------------------------------------------- /amchar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo characteristics 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMCHAR_H 10 | #define AMCHAR_H 11 | 12 | #include "jni/bluetooth.h" 13 | #include "att.h" 14 | 15 | enum { 16 | STD_UUID_CCC = 0, 17 | AMIIGO_UUID_SERVICE, 18 | AMIIGO_UUID_STATUS, 19 | AMIIGO_UUID_CONFIG, 20 | AMIIGO_UUID_LOGBLOCK, 21 | AMIIGO_UUID_FIRMWARE, 22 | AMIIGO_UUID_DEBUG, 23 | AMIIGO_UUID_BUILD, 24 | AMIIGO_UUID_VERSION, 25 | 26 | AMIIGO_UUID_COUNT // This must be the last 27 | }; 28 | 29 | extern struct gatt_char g_char[AMIIGO_UUID_COUNT]; 30 | 31 | #endif // include guard 32 | -------------------------------------------------------------------------------- /gapproto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GAP protocol 3 | * 4 | * @date March 8, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef GAPPROTO_H 10 | #define GAPPROTO_H 11 | 12 | int exec_read(int sock, uint16_t handle); 13 | 14 | int exec_write(int sock, uint16_t handle, const uint8_t * value, size_t vlen); 15 | 16 | int exec_write_req(int sock, uint16_t handle, const uint8_t * value, size_t vlen); 17 | 18 | int discover_handles(int sock, uint16_t start_handle, uint16_t end_handle); 19 | 20 | int gap_connect(const char * src, const char * dst); 21 | 22 | int gap_recv(int sock, void * buf, size_t buflen); 23 | 24 | int gap_shutdown(int sock); 25 | 26 | #endif // include guard 27 | -------------------------------------------------------------------------------- /amproto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo low-level protocol 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMPROTO_H 10 | #define AMPROTO_H 11 | 12 | #include "amcmd.h" 13 | 14 | int exec_status(int sock); 15 | int exec_extstatus(int sock); 16 | int exec_fwupdate(int sock); 17 | int exec_debug_i2c(int sock); 18 | int exec_download(int sock); 19 | int exec_configls(int sock); 20 | int exec_configaccel(int sock); 21 | int exec_configtemp(int sock); 22 | int exec_test_seq(int sock); 23 | int exec_blink(int sock); 24 | int exec_deepsleep(int sock); 25 | int exec_tag(int sock); 26 | int exec_rename(int sock); 27 | int exec_reset(int sock, AMIIGO_CMD cmd); 28 | int discover_handles(int sock, uint16_t start_handle, uint16_t end_handle); 29 | 30 | #endif // include guard 31 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link common 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef COMMON_H 10 | #define COMMON_H 11 | 12 | #define FW_VERSION(Major, Minor, Build) (Major * 100000u + Minor * 1000u + Build) 13 | 14 | typedef struct _aml_options { 15 | int leave_compressed; // If packets should be left in compressed form 16 | int raw; // If should download logs in raw format (no compression in firmware) 17 | int verbosity; // verbose output 18 | int live; // if live output is needed 19 | int console; // if should print accel to console 20 | int append; // if should append instead of creating new files 21 | int full; // If full characteristcs should be discovered 22 | } aml_options_t; 23 | 24 | extern aml_options_t g_opt; 25 | 26 | #endif // include guard 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ======= 2 | License 3 | ======= 4 | 5 | amiigo-link is distributed under GPLv2 license. 6 | 7 | Copyright (c) 2014-2016, Amiigo, Inc. 8 | All rights reserved. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS 11 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 13 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 14 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 15 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 16 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 17 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 18 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 19 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 20 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 | 22 | -------------------------------------------------------------------------------- /amchar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo characteristics 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "amchar.h" 15 | 16 | struct gatt_char g_char[AMIIGO_UUID_COUNT]; 17 | 18 | // Client configuration (for notification and indication) 19 | const char * g_szUUID[] = { 20 | "00002902-0000-1000-8000-00805f9b34fb", 21 | "cca31000-78c6-4785-9e45-0887d451317c", 22 | "cca30001-78c6-4785-9e45-0887d451317c", 23 | "cca30002-78c6-4785-9e45-0887d451317c", 24 | "cca30003-78c6-4785-9e45-0887d451317c", 25 | "cca30004-78c6-4785-9e45-0887d451317c", 26 | "cca30005-78c6-4785-9e45-0887d451317c", 27 | "cca30006-78c6-4785-9e45-0887d451317c", 28 | "cca30007-78c6-4785-9e45-0887d451317c", 29 | }; 30 | 31 | // Initialize the characteristics with Amiigo defaults 32 | void char_init() { 33 | memset(g_char, 0, sizeof(g_char)); 34 | int i; 35 | for (i = 0; i < AMIIGO_UUID_COUNT; ++i) 36 | bt_string_to_uuid(&g_char[i].uuid, g_szUUID[i]); 37 | 38 | // Set default handles 39 | g_char[AMIIGO_UUID_STATUS].value_handle = 0x0025; 40 | g_char[AMIIGO_UUID_CONFIG].value_handle = 0x0027; 41 | g_char[AMIIGO_UUID_LOGBLOCK].value_handle = 0x0029; 42 | g_char[AMIIGO_UUID_FIRMWARE].value_handle = 0x002c; 43 | g_char[AMIIGO_UUID_DEBUG].value_handle = 0x002e; 44 | g_char[AMIIGO_UUID_BUILD].value_handle = 0x0030; 45 | g_char[AMIIGO_UUID_VERSION].value_handle = 0x0032; 46 | } 47 | -------------------------------------------------------------------------------- /amoldproto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Old Amiigo low-level protocol for backward compatibility 3 | * 4 | * @date March 14, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | * 8 | * @notes: 9 | * 10 | * same as amproto.c 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "amidefs.h" 21 | #include "common.h" 22 | #include "gapproto.h" 23 | #include "amoldproto.h" 24 | #include "amchar.h" 25 | #include "amcmd.h" 26 | 27 | // Start configuration of light sensors 28 | int exec_configls_18116(int sock) { 29 | 30 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 31 | if (handle == 0) 32 | return -1; // Not ready yet 33 | 34 | WEDConfig_1816 config; 35 | memset(&config, 0, sizeof(config)); 36 | config.config_type = WED_CFG_LS; 37 | // backward compatibility 38 | 39 | config.lightsensor.fast_interval = g_cfg.config_ls.fast_interval; 40 | config.lightsensor.slow_interval = g_cfg.config_ls.slow_interval; 41 | config.lightsensor.sleep_interval = g_cfg.config_ls.sleep_interval; 42 | config.lightsensor.duration = g_cfg.config_ls.manual_duration; 43 | config.lightsensor.debug = g_cfg.config_ls.debug; 44 | config.lightsensor.movement = g_cfg.config_ls.movement; 45 | config.lightsensor.flags = g_cfg.config_ls.flags; 46 | 47 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.lightsensor)); 48 | if (ret) 49 | return -1; 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /amoldproto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Old Amiigo protocol and definitions for backward compatibility 3 | * 4 | * @date March 14, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMOLDPROTO_H 10 | #define AMOLDPROTO_H 11 | 12 | #include "amidefs.h" 13 | #include "amproto.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | typedef struct { 20 | uint8 unused0; 21 | uint8 unused1; 22 | 23 | // Samples will be taken at the above rate for 'duration' seconds 24 | // every 'interval' seconds. Sampling is disabled if interval is 0. 25 | uint16 fast_interval; 26 | uint16 slow_interval; 27 | uint16 sleep_interval; 28 | uint8 duration; 29 | 30 | uint8 unused2; 31 | uint8 unused3; 32 | uint8 unused4; 33 | uint8 unused5; 34 | 35 | uint8 debug; // Console output debug level, set to 0 for normal operation 36 | uint8 unused6; 37 | uint8 unused7; 38 | uint8 movement; // average movement level at wich starting a reading is allowed 39 | uint8 flags; // Contol Bits 40 | } PACKED WEDConfigLS_1816; 41 | 42 | // Top-level struct for characteristic UUID AMI_UUID(WED_UUID_CONFIG) 43 | typedef struct { 44 | // WED_CFG_TYPE identifying following struct type 45 | uint8 config_type; 46 | 47 | // Structure corresponding to config_type 48 | union { 49 | WEDConfigGeneral general; 50 | WEDConfigAccel accel; 51 | WEDConfigLS_1816 lightsensor; 52 | WEDConfigTemp temp; 53 | WEDConfigMaint maint; 54 | WEDConfigLog log; 55 | WEDConfigConn conn; 56 | WEDConfigName name; 57 | }; 58 | } PACKED WEDConfig_1816; 59 | 60 | int exec_configls_18116(int sock); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif // include guard 67 | -------------------------------------------------------------------------------- /jni/sco.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2002-2003 Maxim Krasnyansky 6 | * Copyright (C) 2002-2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef __SCO_H 26 | #define __SCO_H 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* SCO defaults */ 33 | #define SCO_DEFAULT_MTU 500 34 | #define SCO_DEFAULT_FLUSH_TO 0xFFFF 35 | 36 | #define SCO_CONN_TIMEOUT (HZ * 40) 37 | #define SCO_DISCONN_TIMEOUT (HZ * 2) 38 | #define SCO_CONN_IDLE_TIMEOUT (HZ * 60) 39 | 40 | /* SCO socket address */ 41 | struct sockaddr_sco { 42 | sa_family_t sco_family; 43 | bdaddr_t sco_bdaddr; 44 | }; 45 | 46 | /* set/get sockopt defines */ 47 | #define SCO_OPTIONS 0x01 48 | struct sco_options { 49 | uint16_t mtu; 50 | }; 51 | 52 | #define SCO_CONNINFO 0x02 53 | struct sco_conninfo { 54 | uint16_t hci_handle; 55 | uint8_t dev_class[3]; 56 | }; 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif /* __SCO_H */ 63 | -------------------------------------------------------------------------------- /amdev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo device 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMDEV_H 10 | #define AMDEV_H 11 | 12 | #include 13 | #include "amidefs.h" 14 | 15 | typedef enum _DISCOVERY_STATE { 16 | STATE_NONE = 0, 17 | STATE_BUILD, 18 | STATE_VERSION, 19 | STATE_STATUS, 20 | STATE_DOWNLOAD, 21 | STATE_FWSTATUS, 22 | STATE_FWSTATUS_WAIT, 23 | STATE_I2C, 24 | STATE_EXTSTATUS, 25 | 26 | STATE_COUNT, // This must be the last 27 | } DISCOVERY_STATE; 28 | 29 | // Keep the state of each device here 30 | typedef struct _amdev { 31 | int dev_idx; // device index 32 | int started; // If command is sent 33 | int done; // If comamnd to do on device is done 34 | DISCOVERY_STATE state; // Device state machine state 35 | int sock; // Socket openned for this device 36 | WEDVersion ver; // Firmware version 37 | unsigned int ver_flat; // Flat version number to compare 38 | WEDStatus status; // Firmware status 39 | struct { 40 | uint8 type; // WED_LOG_TAG 41 | // Tag data from WED_MAINT_TAG command 42 | uint32_t tag; 43 | } PACKED logTag; // Last tag 44 | WEDLogTimestamp logTime; // Last timestamp packet 45 | WEDLogAccel logAccel; // Last accel 46 | uint32_t read_logs; // Logs downloaded so far 47 | uint32_t total_logs; // Total number of logs tp be downloaded 48 | int bValidAccel; // If any uncompressed accel is received 49 | char szBuild[512]; // Firmware build text 50 | char szVersion[512]; // Firmware version text 51 | FILE * logFile; // file to download logs 52 | } amdev_t; 53 | 54 | #endif // include guard 55 | -------------------------------------------------------------------------------- /amcmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo commands and configs 3 | * 4 | * @date March 9, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #ifndef AMCMD_H 10 | #define AMCMD_H 11 | 12 | #include "amidefs.h" 13 | 14 | typedef enum _AMIIGO_CMD { 15 | AMIIGO_CMD_NONE = 0, // Just to do a connection status test 16 | AMIIGO_CMD_FWUPDATE, // Firmware update 17 | AMIIGO_CMD_RESET_LOGS, // Reset log buffer 18 | AMIIGO_CMD_RESET_CPU, // Reset CPU 19 | AMIIGO_CMD_RESET_CONFIGS, // Reset configurations to default 20 | AMIIGO_CMD_DOWNLOAD, // Download all the logs 21 | AMIIGO_CMD_CONFIGLS, // Configure light sensors 22 | AMIIGO_CMD_CONFIGACCEL, // Configure acceleration sensors 23 | AMIIGO_CMD_CONFIGTEMP, // Configure temperature sensor 24 | AMIIGO_CMD_BLINK, // Configure a single blink 25 | AMIIGO_CMD_DEEPSLEEP, // Go to deep sleep until double tap 26 | AMIIGO_CMD_I2C_READ, // Read i2c address and register 27 | AMIIGO_CMD_I2C_WRITE, // Write to i2c address and register 28 | AMIIGO_CMD_RENAME, // Rename the WED 29 | AMIIGO_CMD_TAG, // Write a tag 30 | AMIIGO_CMD_TEST_SEQ, // Accel test sequence command 31 | AMIIGO_CMD_EXTSTATUS, // Extended status 32 | } AMIIGO_CMD; 33 | 34 | #define MAX_DEV_COUNT 10 // Maximum number of devices to work with 35 | typedef struct amiigo_config { 36 | WEDDebugI2CCmd i2c; // i2c debugging 37 | WEDConfigLS config_ls; // Light configuration 38 | WEDConfigAccel config_accel; // Acceleration sensors configuration 39 | WEDConfigTemp config_temp; // Temperature sensor configuration 40 | WEDConfigName name; // WED name 41 | WEDMaintLED maint_led; // Blink command 42 | WEDConfigGeneral general; // For tags 43 | uint8 test_mode; // accel test mode 44 | // Device and interface to use 45 | int count_dst; 46 | char * dst[MAX_DEV_COUNT]; 47 | } amcfg_t; 48 | 49 | extern AMIIGO_CMD g_cmd; 50 | 51 | // Parsed config that goes with the command 52 | extern amcfg_t g_cfg; 53 | 54 | #endif // include guard 55 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ###################################################################################### 2 | ## 3 | ## Makefile for Amiigo link 4 | ## 5 | ## Author: dashesy 6 | ## 7 | ## 8 | ## Major targets: 9 | ## all - make all the following targets: 10 | ## 11 | ## Special targets: 12 | ## install - place all scripts and binaries in the conventional directories 13 | ## clean - clean up 14 | ## 15 | ###################################################################################### 16 | 17 | #========================================================================== 18 | # UTILITIES 19 | #========================================================================== 20 | MKPARENT := mkdir -p `dirname $(1)` 21 | ECHO := @echo 22 | CP := @cp 23 | 24 | 25 | #========================================================================== 26 | # CONSTANTS 27 | #========================================================================== 28 | 29 | CC := gcc 30 | CXX := g++ 31 | 32 | OUTPUTBIN = amlink 33 | 34 | # Additional libraries 35 | LIBS := 36 | 37 | LFLAGS = $(LIBDIRS) $(LIBS) 38 | 39 | INCLUDEDIRS := -I. 40 | 41 | CFLAGS := -Wall $(INCLUDEDIRS) 42 | 43 | # common sources 44 | COMMON_SRC := ./main.c \ 45 | ./btio.c \ 46 | ./att.c \ 47 | ./hcitool.c \ 48 | ./gapproto.c \ 49 | ./amlprocess.c \ 50 | ./amproto.c \ 51 | ./cmdparse.c \ 52 | ./amchar.c \ 53 | ./fwupdate.c \ 54 | ./amoldproto.c \ 55 | 56 | # Avoid the need to latest BlueZ 57 | COMMON_SRC += jni/bluetooth.c\ 58 | jni/hci.c \ 59 | 60 | COMMON_OBJS := $(patsubst %.c, .obj/%.o, $(notdir $(COMMON_SRC))) 61 | 62 | VPATH := $(sort $(dir $(COMMON_SRC))) 63 | 64 | all: prepare ./$(OUTPUTBIN) 65 | 66 | install: 67 | @cp ./$(OUTPUTBIN) /usr/bin/$(OUTPUTBIN) 68 | chmod +s /usr/bin/$(OUTPUTBIN) 69 | 70 | .PHONY: prepare 71 | prepare: 72 | @mkdir -p .obj 73 | 74 | .PHONY: clean 75 | clean: 76 | rm -rf .obj 77 | rm -f ./$(OUTPUTBIN) 78 | 79 | 80 | # the "common" object files 81 | .obj/%.o : %.cpp Makefile 82 | @echo creating $@ ... 83 | $(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< 84 | 85 | .obj/%.o : %.c Makefile 86 | @echo creating $@ ... 87 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< 88 | 89 | # This will make the output 90 | ./$(OUTPUTBIN): $(COMMON_OBJS) 91 | @echo building output ... 92 | $(CC) -o $(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS) 93 | 94 | -------------------------------------------------------------------------------- /jni/rfcomm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2002-2003 Maxim Krasnyansky 6 | * Copyright (C) 2002-2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef __RFCOMM_H 26 | #define __RFCOMM_H 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #include 33 | 34 | /* RFCOMM defaults */ 35 | #define RFCOMM_DEFAULT_MTU 127 36 | 37 | #define RFCOMM_PSM 3 38 | 39 | /* RFCOMM socket address */ 40 | struct sockaddr_rc { 41 | sa_family_t rc_family; 42 | bdaddr_t rc_bdaddr; 43 | uint8_t rc_channel; 44 | }; 45 | 46 | /* RFCOMM socket options */ 47 | #define RFCOMM_CONNINFO 0x02 48 | struct rfcomm_conninfo { 49 | uint16_t hci_handle; 50 | uint8_t dev_class[3]; 51 | }; 52 | 53 | #define RFCOMM_LM 0x03 54 | #define RFCOMM_LM_MASTER 0x0001 55 | #define RFCOMM_LM_AUTH 0x0002 56 | #define RFCOMM_LM_ENCRYPT 0x0004 57 | #define RFCOMM_LM_TRUSTED 0x0008 58 | #define RFCOMM_LM_RELIABLE 0x0010 59 | #define RFCOMM_LM_SECURE 0x0020 60 | 61 | /* RFCOMM TTY support */ 62 | #define RFCOMM_MAX_DEV 256 63 | 64 | #define RFCOMMCREATEDEV _IOW('R', 200, int) 65 | #define RFCOMMRELEASEDEV _IOW('R', 201, int) 66 | #define RFCOMMGETDEVLIST _IOR('R', 210, int) 67 | #define RFCOMMGETDEVINFO _IOR('R', 211, int) 68 | 69 | struct rfcomm_dev_req { 70 | int16_t dev_id; 71 | uint32_t flags; 72 | bdaddr_t src; 73 | bdaddr_t dst; 74 | uint8_t channel; 75 | }; 76 | #define RFCOMM_REUSE_DLC 0 77 | #define RFCOMM_RELEASE_ONHUP 1 78 | #define RFCOMM_HANGUP_NOW 2 79 | #define RFCOMM_TTY_ATTACHED 3 80 | 81 | struct rfcomm_dev_info { 82 | int16_t id; 83 | uint32_t flags; 84 | uint16_t state; 85 | bdaddr_t src; 86 | bdaddr_t dst; 87 | uint8_t channel; 88 | }; 89 | 90 | struct rfcomm_dev_list_req { 91 | uint16_t dev_num; 92 | struct rfcomm_dev_info dev_info[0]; 93 | }; 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif /* __RFCOMM_H */ 100 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # This file is NOT licensed under the GPLv3, which is the license for the rest 2 | # of YouCompleteMe. 3 | # 4 | # Here's the license text for this file: 5 | # 6 | # This is free and unencumbered software released into the public domain. 7 | # 8 | # Anyone is free to copy, modify, publish, use, compile, sell, or 9 | # distribute this software, either in source code form or as a compiled 10 | # binary, for any purpose, commercial or non-commercial, and by any 11 | # means. 12 | # 13 | # In jurisdictions that recognize copyright laws, the author or authors 14 | # of this software dedicate any and all copyright interest in the 15 | # software to the public domain. We make this dedication for the benefit 16 | # of the public at large and to the detriment of our heirs and 17 | # successors. We intend this dedication to be an overt act of 18 | # relinquishment in perpetuity of all present and future rights to this 19 | # software under copyright law. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # For more information, please refer to 30 | 31 | import os 32 | import ycm_core 33 | 34 | # These are the compilation flags that will be used in case there's no 35 | # compilation database set (by default, one is not set). 36 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 37 | flags = [ 38 | '-Wall', 39 | '-Wextra', 40 | '-Werror', 41 | '-Wc++98-compat', 42 | '-Wno-long-long', 43 | '-Wno-variadic-macros', 44 | '-fexceptions', 45 | '-DNDEBUG', 46 | '-DUSE_CLANG_COMPLETER', 47 | # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which 48 | # language to use when compiling headers. So it will guess. Badly. So C++ 49 | # headers will be compiled as C headers. You don't want that so ALWAYS specify 50 | # a "-std=". 51 | # For a C project, you would set this to something like 'c99' instead of 52 | # 'c++11'. 53 | '-std=c99', 54 | # ...and the same thing goes for the magic -x option which specifies the 55 | # language that the files to be compiled are written in. This is mostly 56 | # relevant for c++ headers. 57 | # For a C project, you would set this to 'c' instead of 'c++'. 58 | '-x', 59 | 'c', 60 | '-isystem', 61 | '../BoostParts', 62 | '-isystem', 63 | # This path will only work on OS X, but extra paths that don't exist are not 64 | # harmful 65 | '/System/Library/Frameworks/Python.framework/Headers', 66 | '-isystem', 67 | '../llvm/include', 68 | '-isystem', 69 | '../llvm/tools/clang/include', 70 | '-I', 71 | '.', 72 | '-I', 73 | './ClangCompleter', 74 | '-isystem', 75 | './tests/gmock/gtest', 76 | '-isystem', 77 | './tests/gmock/gtest/include', 78 | '-isystem', 79 | './tests/gmock', 80 | '-isystem', 81 | './tests/gmock/include' 82 | ] 83 | 84 | # Set this to the absolute path to the folder (NOT the file!) containing the 85 | # compile_commands.json file to use that instead of 'flags'. See here for 86 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 87 | # 88 | # Most projects will NOT need to set this to anything; you can just change the 89 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 90 | compilation_database_folder = '' 91 | 92 | if compilation_database_folder: 93 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 94 | else: 95 | database = None 96 | 97 | 98 | def DirectoryOfThisScript(): 99 | return os.path.dirname( os.path.abspath( __file__ ) ) 100 | 101 | 102 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 103 | if not working_directory: 104 | return list( flags ) 105 | new_flags = [] 106 | make_next_absolute = False 107 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 108 | for flag in flags: 109 | new_flag = flag 110 | 111 | if make_next_absolute: 112 | make_next_absolute = False 113 | if not flag.startswith( '/' ): 114 | new_flag = os.path.join( working_directory, flag ) 115 | 116 | for path_flag in path_flags: 117 | if flag == path_flag: 118 | make_next_absolute = True 119 | break 120 | 121 | if flag.startswith( path_flag ): 122 | path = flag[ len( path_flag ): ] 123 | new_flag = path_flag + os.path.join( working_directory, path ) 124 | break 125 | 126 | if new_flag: 127 | new_flags.append( new_flag ) 128 | return new_flags 129 | 130 | 131 | def FlagsForFile( filename ): 132 | if database: 133 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 134 | # python list, but a "list-like" StringVec object 135 | compilation_info = database.GetCompilationInfoForFile( filename ) 136 | final_flags = MakeRelativePathsInFlagsAbsolute( 137 | compilation_info.compiler_flags_, 138 | compilation_info.compiler_working_dir_ ) 139 | 140 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 141 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 142 | # ycm_extra_conf IF YOU'RE NOT 100% YOU NEED IT. 143 | try: 144 | final_flags.remove( '-stdlib=libc++' ) 145 | except ValueError: 146 | pass 147 | else: 148 | relative_to = DirectoryOfThisScript() 149 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 150 | 151 | return { 152 | 'flags': final_flags, 153 | 'do_cache': True 154 | } 155 | -------------------------------------------------------------------------------- /btio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2009-2010 Marcel Holtmann 6 | * Copyright (C) 2009-2010 Nokia Corporation 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | /* 26 | * This code was originally part of the BlueZ protocol stack (hence the comments above) 27 | * but has been heavily modified to remove dependencies on glib, and make it a true low-level 28 | * protocol stack. 29 | */ 30 | 31 | #ifndef BT_IO_H 32 | #define BT_IO_H 33 | 34 | #include 35 | 36 | /* Attribute Protocol Opcodes */ 37 | #define ATT_OP_ERROR 0x01 38 | #define ATT_OP_MTU_REQ 0x02 39 | #define ATT_OP_MTU_RESP 0x03 40 | #define ATT_OP_FIND_INFO_REQ 0x04 41 | #define ATT_OP_FIND_INFO_RESP 0x05 42 | #define ATT_OP_FIND_BY_TYPE_REQ 0x06 43 | #define ATT_OP_FIND_BY_TYPE_RESP 0x07 44 | #define ATT_OP_READ_BY_TYPE_REQ 0x08 45 | #define ATT_OP_READ_BY_TYPE_RESP 0x09 46 | #define ATT_OP_READ_REQ 0x0A 47 | #define ATT_OP_READ_RESP 0x0B 48 | #define ATT_OP_READ_BLOB_REQ 0x0C 49 | #define ATT_OP_READ_BLOB_RESP 0x0D 50 | #define ATT_OP_READ_MULTI_REQ 0x0E 51 | #define ATT_OP_READ_MULTI_RESP 0x0F 52 | #define ATT_OP_READ_BY_GROUP_REQ 0x10 53 | #define ATT_OP_READ_BY_GROUP_RESP 0x11 54 | #define ATT_OP_WRITE_REQ 0x12 55 | #define ATT_OP_WRITE_RESP 0x13 56 | #define ATT_OP_WRITE_CMD 0x52 57 | #define ATT_OP_PREP_WRITE_REQ 0x16 58 | #define ATT_OP_PREP_WRITE_RESP 0x17 59 | #define ATT_OP_EXEC_WRITE_REQ 0x18 60 | #define ATT_OP_EXEC_WRITE_RESP 0x19 61 | #define ATT_OP_HANDLE_NOTIFY 0x1B 62 | #define ATT_OP_HANDLE_IND 0x1D 63 | #define ATT_OP_HANDLE_CNF 0x1E 64 | #define ATT_OP_SIGNED_WRITE_CMD 0xD2 65 | 66 | /* Error codes for Error response PDU */ 67 | #define ATT_ECODE_INVALID_HANDLE 0x01 68 | #define ATT_ECODE_READ_NOT_PERM 0x02 69 | #define ATT_ECODE_WRITE_NOT_PERM 0x03 70 | #define ATT_ECODE_INVALID_PDU 0x04 71 | #define ATT_ECODE_AUTHENTICATION 0x05 72 | #define ATT_ECODE_REQ_NOT_SUPP 0x06 73 | #define ATT_ECODE_INVALID_OFFSET 0x07 74 | #define ATT_ECODE_AUTHORIZATION 0x08 75 | #define ATT_ECODE_PREP_QUEUE_FULL 0x09 76 | #define ATT_ECODE_ATTR_NOT_FOUND 0x0A 77 | #define ATT_ECODE_ATTR_NOT_LONG 0x0B 78 | #define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C 79 | #define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D 80 | #define ATT_ECODE_UNLIKELY 0x0E 81 | #define ATT_ECODE_INSUFF_ENC 0x0F 82 | #define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 83 | #define ATT_ECODE_INSUFF_RESOURCES 0x11 84 | /* Application error */ 85 | #define ATT_ECODE_IO 0x80 86 | #define ATT_ECODE_TIMEOUT 0x81 87 | #define ATT_ECODE_ABORTED 0x82 88 | 89 | /* Characteristic Property bit field */ 90 | #define ATT_CHAR_PROPER_BROADCAST 0x01 91 | #define ATT_CHAR_PROPER_READ 0x02 92 | #define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP 0x04 93 | #define ATT_CHAR_PROPER_WRITE 0x08 94 | #define ATT_CHAR_PROPER_NOTIFY 0x10 95 | #define ATT_CHAR_PROPER_INDICATE 0x20 96 | #define ATT_CHAR_PROPER_AUTH 0x40 97 | #define ATT_CHAR_PROPER_EXT_PROPER 0x80 98 | 99 | #define ATT_MAX_VALUE_LEN 512 100 | #define ATT_DEFAULT_L2CAP_MTU 48 101 | #define ATT_DEFAULT_LE_MTU 23 102 | 103 | #define ATT_CID 4 104 | #define ATT_PSM 31 105 | 106 | /* Flags for Execute Write Request Operation */ 107 | #define ATT_CANCEL_ALL_PREP_WRITES 0x00 108 | #define ATT_WRITE_ALL_PREP_WRITES 0x01 109 | 110 | /* Find Information Response Formats */ 111 | #define ATT_FIND_INFO_RESP_FMT_16BIT 0x01 112 | #define ATT_FIND_INFO_RESP_FMT_128BIT 0x02 113 | 114 | typedef enum { 115 | BT_IO_OPT_INVALID = 0, 116 | BT_IO_OPT_SOURCE, 117 | BT_IO_OPT_SOURCE_BDADDR, 118 | BT_IO_OPT_SOURCE_TYPE, 119 | BT_IO_OPT_DEST, 120 | BT_IO_OPT_DEST_BDADDR, 121 | BT_IO_OPT_DEST_TYPE, 122 | BT_IO_OPT_DEFER_TIMEOUT, 123 | BT_IO_OPT_SEC_LEVEL, 124 | BT_IO_OPT_KEY_SIZE, 125 | BT_IO_OPT_CHANNEL, 126 | BT_IO_OPT_SOURCE_CHANNEL, 127 | BT_IO_OPT_DEST_CHANNEL, 128 | BT_IO_OPT_PSM, 129 | BT_IO_OPT_CID, 130 | BT_IO_OPT_MTU, 131 | BT_IO_OPT_OMTU, 132 | BT_IO_OPT_IMTU, 133 | BT_IO_OPT_MASTER, 134 | BT_IO_OPT_HANDLE, 135 | BT_IO_OPT_CLASS, 136 | BT_IO_OPT_MODE, 137 | BT_IO_OPT_FLUSHABLE, 138 | BT_IO_OPT_PRIORITY, 139 | } BtIOOption; 140 | 141 | typedef enum { 142 | BT_IO_SEC_SDP = 0, BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH, 143 | } BtIOSecLevel; 144 | 145 | typedef enum { 146 | BT_IO_MODE_BASIC = 0, 147 | BT_IO_MODE_RETRANS, 148 | BT_IO_MODE_FLOWCTL, 149 | BT_IO_MODE_ERTM, 150 | BT_IO_MODE_STREAMING 151 | } BtIOMode; 152 | 153 | typedef enum { 154 | BT_IO_L2CAP, BT_IO_RFCOMM, BT_IO_SCO, BT_IO_INVALID, 155 | } BtIOType; 156 | 157 | struct set_opts { 158 | bdaddr_t src; 159 | bdaddr_t dst; 160 | BtIOType type; 161 | uint8_t src_type; 162 | uint8_t dst_type; 163 | int defer; 164 | int sec_level; 165 | uint8_t channel; 166 | uint16_t psm; 167 | uint16_t cid; 168 | uint16_t mtu; 169 | uint16_t imtu; 170 | uint16_t omtu; 171 | int master; 172 | uint8_t mode; 173 | int flushable; 174 | uint32_t priority; 175 | }; 176 | 177 | bool bt_io_accept(int sock); 178 | 179 | bool bt_io_set(int sock, struct set_opts *opts); 180 | 181 | bool bt_io_get(int sock, BtIOOption opt1, ...); 182 | 183 | int bt_io_connect(struct set_opts* opts); 184 | 185 | int bt_io_listen(struct set_opts* opts); 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /jni/l2cap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2000-2001 Qualcomm Incorporated 6 | * Copyright (C) 2002-2003 Maxim Krasnyansky 7 | * Copyright (C) 2002-2010 Marcel Holtmann 8 | * Copyright (c) 2012 Code Aurora Forum. All rights reserved. 9 | * 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef __L2CAP_H 28 | #define __L2CAP_H 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #include 35 | 36 | /* L2CAP defaults */ 37 | #define L2CAP_DEFAULT_MTU 672 38 | #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF 39 | 40 | /* L2CAP socket address */ 41 | struct sockaddr_l2 { 42 | sa_family_t l2_family; 43 | unsigned short l2_psm; 44 | bdaddr_t l2_bdaddr; 45 | unsigned short l2_cid; 46 | uint8_t l2_bdaddr_type; 47 | }; 48 | 49 | /* L2CAP socket options */ 50 | #define L2CAP_OPTIONS 0x01 51 | struct l2cap_options { 52 | uint16_t omtu; 53 | uint16_t imtu; 54 | uint16_t flush_to; 55 | uint8_t mode; 56 | uint8_t fcs; 57 | uint8_t max_tx; 58 | uint16_t txwin_size; 59 | }; 60 | 61 | #define L2CAP_CONNINFO 0x02 62 | struct l2cap_conninfo { 63 | uint16_t hci_handle; 64 | uint8_t dev_class[3]; 65 | }; 66 | 67 | #define L2CAP_LM 0x03 68 | #define L2CAP_LM_MASTER 0x0001 69 | #define L2CAP_LM_AUTH 0x0002 70 | #define L2CAP_LM_ENCRYPT 0x0004 71 | #define L2CAP_LM_TRUSTED 0x0008 72 | #define L2CAP_LM_RELIABLE 0x0010 73 | #define L2CAP_LM_SECURE 0x0020 74 | 75 | /* L2CAP command codes */ 76 | #define L2CAP_COMMAND_REJ 0x01 77 | #define L2CAP_CONN_REQ 0x02 78 | #define L2CAP_CONN_RSP 0x03 79 | #define L2CAP_CONF_REQ 0x04 80 | #define L2CAP_CONF_RSP 0x05 81 | #define L2CAP_DISCONN_REQ 0x06 82 | #define L2CAP_DISCONN_RSP 0x07 83 | #define L2CAP_ECHO_REQ 0x08 84 | #define L2CAP_ECHO_RSP 0x09 85 | #define L2CAP_INFO_REQ 0x0a 86 | #define L2CAP_INFO_RSP 0x0b 87 | #define L2CAP_CREATE_REQ 0x0c 88 | #define L2CAP_CREATE_RSP 0x0d 89 | #define L2CAP_MOVE_REQ 0x0e 90 | #define L2CAP_MOVE_RSP 0x0f 91 | #define L2CAP_MOVE_CFM 0x10 92 | #define L2CAP_MOVE_CFM_RSP 0x11 93 | 94 | /* L2CAP extended feature mask */ 95 | #define L2CAP_FEAT_FLOWCTL 0x00000001 96 | #define L2CAP_FEAT_RETRANS 0x00000002 97 | #define L2CAP_FEAT_BIDIR_QOS 0x00000004 98 | #define L2CAP_FEAT_ERTM 0x00000008 99 | #define L2CAP_FEAT_STREAMING 0x00000010 100 | #define L2CAP_FEAT_FCS 0x00000020 101 | #define L2CAP_FEAT_EXT_FLOW 0x00000040 102 | #define L2CAP_FEAT_FIXED_CHAN 0x00000080 103 | #define L2CAP_FEAT_EXT_WINDOW 0x00000100 104 | #define L2CAP_FEAT_UCD 0x00000200 105 | 106 | /* L2CAP fixed channels */ 107 | #define L2CAP_FC_L2CAP 0x02 108 | #define L2CAP_FC_CONNLESS 0x04 109 | #define L2CAP_FC_A2MP 0x08 110 | 111 | /* L2CAP structures */ 112 | typedef struct { 113 | uint16_t len; 114 | uint16_t cid; 115 | } __attribute__ ((packed)) l2cap_hdr; 116 | #define L2CAP_HDR_SIZE 4 117 | 118 | typedef struct { 119 | uint8_t code; 120 | uint8_t ident; 121 | uint16_t len; 122 | } __attribute__ ((packed)) l2cap_cmd_hdr; 123 | #define L2CAP_CMD_HDR_SIZE 4 124 | 125 | typedef struct { 126 | uint16_t reason; 127 | } __attribute__ ((packed)) l2cap_cmd_rej; 128 | #define L2CAP_CMD_REJ_SIZE 2 129 | 130 | typedef struct { 131 | uint16_t psm; 132 | uint16_t scid; 133 | } __attribute__ ((packed)) l2cap_conn_req; 134 | #define L2CAP_CONN_REQ_SIZE 4 135 | 136 | typedef struct { 137 | uint16_t dcid; 138 | uint16_t scid; 139 | uint16_t result; 140 | uint16_t status; 141 | } __attribute__ ((packed)) l2cap_conn_rsp; 142 | #define L2CAP_CONN_RSP_SIZE 8 143 | 144 | /* connect result */ 145 | #define L2CAP_CR_SUCCESS 0x0000 146 | #define L2CAP_CR_PEND 0x0001 147 | #define L2CAP_CR_BAD_PSM 0x0002 148 | #define L2CAP_CR_SEC_BLOCK 0x0003 149 | #define L2CAP_CR_NO_MEM 0x0004 150 | 151 | /* connect status */ 152 | #define L2CAP_CS_NO_INFO 0x0000 153 | #define L2CAP_CS_AUTHEN_PEND 0x0001 154 | #define L2CAP_CS_AUTHOR_PEND 0x0002 155 | 156 | typedef struct { 157 | uint16_t dcid; 158 | uint16_t flags; 159 | uint8_t data[0]; 160 | } __attribute__ ((packed)) l2cap_conf_req; 161 | #define L2CAP_CONF_REQ_SIZE 4 162 | 163 | typedef struct { 164 | uint16_t scid; 165 | uint16_t flags; 166 | uint16_t result; 167 | uint8_t data[0]; 168 | } __attribute__ ((packed)) l2cap_conf_rsp; 169 | #define L2CAP_CONF_RSP_SIZE 6 170 | 171 | #define L2CAP_CONF_SUCCESS 0x0000 172 | #define L2CAP_CONF_UNACCEPT 0x0001 173 | #define L2CAP_CONF_REJECT 0x0002 174 | #define L2CAP_CONF_UNKNOWN 0x0003 175 | #define L2CAP_CONF_PENDING 0x0004 176 | #define L2CAP_CONF_EFS_REJECT 0x0005 177 | 178 | typedef struct { 179 | uint8_t type; 180 | uint8_t len; 181 | uint8_t val[0]; 182 | } __attribute__ ((packed)) l2cap_conf_opt; 183 | #define L2CAP_CONF_OPT_SIZE 2 184 | 185 | #define L2CAP_CONF_MTU 0x01 186 | #define L2CAP_CONF_FLUSH_TO 0x02 187 | #define L2CAP_CONF_QOS 0x03 188 | #define L2CAP_CONF_RFC 0x04 189 | #define L2CAP_CONF_FCS 0x05 190 | #define L2CAP_CONF_EFS 0x06 191 | #define L2CAP_CONF_EWS 0x07 192 | 193 | #define L2CAP_CONF_MAX_SIZE 22 194 | 195 | #define L2CAP_MODE_BASIC 0x00 196 | #define L2CAP_MODE_RETRANS 0x01 197 | #define L2CAP_MODE_FLOWCTL 0x02 198 | #define L2CAP_MODE_ERTM 0x03 199 | #define L2CAP_MODE_STREAMING 0x04 200 | 201 | #define L2CAP_SERVTYPE_NOTRAFFIC 0x00 202 | #define L2CAP_SERVTYPE_BESTEFFORT 0x01 203 | #define L2CAP_SERVTYPE_GUARANTEED 0x02 204 | 205 | typedef struct { 206 | uint16_t dcid; 207 | uint16_t scid; 208 | } __attribute__ ((packed)) l2cap_disconn_req; 209 | #define L2CAP_DISCONN_REQ_SIZE 4 210 | 211 | typedef struct { 212 | uint16_t dcid; 213 | uint16_t scid; 214 | } __attribute__ ((packed)) l2cap_disconn_rsp; 215 | #define L2CAP_DISCONN_RSP_SIZE 4 216 | 217 | typedef struct { 218 | uint16_t type; 219 | } __attribute__ ((packed)) l2cap_info_req; 220 | #define L2CAP_INFO_REQ_SIZE 2 221 | 222 | typedef struct { 223 | uint16_t type; 224 | uint16_t result; 225 | uint8_t data[0]; 226 | } __attribute__ ((packed)) l2cap_info_rsp; 227 | #define L2CAP_INFO_RSP_SIZE 4 228 | 229 | /* info type */ 230 | #define L2CAP_IT_CL_MTU 0x0001 231 | #define L2CAP_IT_FEAT_MASK 0x0002 232 | 233 | /* info result */ 234 | #define L2CAP_IR_SUCCESS 0x0000 235 | #define L2CAP_IR_NOTSUPP 0x0001 236 | 237 | typedef struct { 238 | uint16_t psm; 239 | uint16_t scid; 240 | uint8_t id; 241 | } __attribute__ ((packed)) l2cap_create_req; 242 | #define L2CAP_CREATE_REQ_SIZE 5 243 | 244 | typedef struct { 245 | uint16_t dcid; 246 | uint16_t scid; 247 | uint16_t result; 248 | uint16_t status; 249 | } __attribute__ ((packed)) l2cap_create_rsp; 250 | #define L2CAP_CREATE_RSP_SIZE 8 251 | 252 | typedef struct { 253 | uint16_t icid; 254 | uint8_t id; 255 | } __attribute__ ((packed)) l2cap_move_req; 256 | #define L2CAP_MOVE_REQ_SIZE 3 257 | 258 | typedef struct { 259 | uint16_t icid; 260 | uint16_t result; 261 | } __attribute__ ((packed)) l2cap_move_rsp; 262 | #define L2CAP_MOVE_RSP_SIZE 4 263 | 264 | typedef struct { 265 | uint16_t icid; 266 | uint16_t result; 267 | } __attribute__ ((packed)) l2cap_move_cfm; 268 | #define L2CAP_MOVE_CFM_SIZE 4 269 | 270 | typedef struct { 271 | uint16_t icid; 272 | } __attribute__ ((packed)) l2cap_move_cfm_rsp; 273 | #define L2CAP_MOVE_CFM_RSP_SIZE 2 274 | 275 | #ifdef __cplusplus 276 | } 277 | #endif 278 | 279 | #endif /* __L2CAP_H */ 280 | -------------------------------------------------------------------------------- /fwupdate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link firmware update process 3 | * 4 | * @date March 10, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "common.h" 21 | #include "amidefs.h" 22 | #include "amdev.h" 23 | #include "amchar.h" 24 | #include "gapproto.h" 25 | #include "amcmd.h" 26 | 27 | #define FWUP_HDR_ID 0x0101 28 | 29 | uint32_t g_fwup_speedup = 1; // How much to overload firmware update 30 | 31 | FILE * g_fwImageFile = NULL; // Firmware image file 32 | uint32_t g_fwImageSize = 0; // Firmware image size in bytes 33 | uint32_t g_fwImageWrittenSize = 0; // bytes transmitted 34 | uint16_t g_fwImagePage = 0; // Firmwate image total pages 35 | uint16_t g_fwImageWrittenPage = 0; // pages transmitted 36 | 37 | int set_update_file(const char * szName) { 38 | g_fwImageFile = fopen(szName, "r"); 39 | if (g_fwImageFile == NULL) { 40 | fprintf(stderr, "Firmware image file (%s) not accessible!\n", szName); 41 | return -1; 42 | } 43 | fseek(g_fwImageFile, 0, SEEK_END); 44 | g_fwImageSize = ftell(g_fwImageFile); 45 | fseek(g_fwImageFile, 0, SEEK_SET); 46 | if (g_fwImageSize < WED_FW_HEADER_SIZE) { 47 | fprintf(stderr, "Firmware image file (%s) too small!\n", szName); 48 | return -1; 49 | } 50 | WEDFirmwareCommand fwcmd; 51 | memset(&fwcmd, 0, sizeof(fwcmd)); 52 | fwcmd.pkt_type = WED_FIRMWARE_INIT; 53 | fread(fwcmd.header, WED_FW_HEADER_SIZE, 1, g_fwImageFile); 54 | 55 | uint16_t * hdr = (uint16_t *) &fwcmd.header[0]; 56 | // TODO: check CRC 57 | //uint16_t fw_crc = hdr[0]; 58 | uint16_t fw_id = hdr[1]; 59 | g_fwImagePage = hdr[2]; 60 | 61 | if (fw_id != FWUP_HDR_ID) { 62 | fprintf(stderr, "Firmware image (%s) invalid!\n", szName); 63 | return -1; 64 | } 65 | 66 | if (WED_FW_BLOCK_SIZE * WED_FW_STREAM_BLOCKS * g_fwImagePage != g_fwImageSize) { 67 | fprintf(stderr, "Firmware image (%s) invalid size!\n", szName); 68 | return -1; 69 | } 70 | 71 | g_fwImageWrittenSize = 0; 72 | g_fwImageWrittenPage = 0; 73 | fseek(g_fwImageFile, 0, SEEK_SET); 74 | 75 | g_cmd = AMIIGO_CMD_FWUPDATE; 76 | return 0; 77 | } 78 | 79 | // Firmware update in progress 80 | int process_fwstatus(amdev_t * dev, uint8_t * buf, ssize_t buflen) { 81 | int ret = 0; 82 | WEDFirmwareStatus fwstatus; 83 | memset(&fwstatus, 0, sizeof(fwstatus)); 84 | fwstatus.status = buf[1]; 85 | fwstatus.error_code = buf[2]; 86 | 87 | uint16_t handle = g_char[AMIIGO_UUID_FIRMWARE].value_handle; 88 | 89 | if (dev->state == STATE_FWSTATUS) 90 | { 91 | if (fwstatus.status != WED_FWSTATUS_IDLE) 92 | { 93 | printf("Unfinished previous update detected.\n" 94 | "Reset CPU and try again\n"); 95 | return -1; 96 | } 97 | } 98 | 99 | if (fwstatus.status == WED_FWSTATUS_WAIT 100 | || fwstatus.status == WED_FWSTATUS_IDLE) { 101 | if (dev->state == STATE_FWSTATUS) 102 | { 103 | WEDFirmwareCommand fwcmd; 104 | memset(&fwcmd, 0, sizeof(fwcmd)); 105 | fwcmd.pkt_type = WED_FIRMWARE_INIT; 106 | fread(fwcmd.header, WED_FW_HEADER_SIZE, 1, g_fwImageFile); 107 | fseek(g_fwImageFile, 0, SEEK_SET); 108 | g_fwImageWrittenSize = 0; 109 | 110 | ret = exec_write(dev->sock, handle, (uint8_t *) &fwcmd, sizeof(fwcmd)); 111 | if (ret) 112 | return -1; 113 | // We have already written the header 114 | dev->state = STATE_FWSTATUS_WAIT; 115 | } 116 | ret = exec_read(dev->sock, handle); // Continue polling 117 | } else if (fwstatus.status == WED_FWSTATUS_ERROR) { 118 | switch (fwstatus.error_code) { 119 | case WED_FWERROR_HEADER: 120 | fprintf(stderr, "Firmware image header was unrecognized\n"); 121 | break; 122 | case WED_FWERROR_SIZE: 123 | fprintf(stderr, "Lost packets or image size was too large\n"); 124 | break; 125 | case WED_FWERROR_CRC: 126 | fprintf(stderr, "CRC check failed\n"); 127 | break; 128 | case WED_FWERROR_FLASH: 129 | fprintf(stderr, "SPI flash error\n"); 130 | break; 131 | case WED_FWERROR_OTHER: 132 | fprintf(stderr, "Internal error\n"); 133 | break; 134 | default: 135 | fprintf(stderr, "Unknown error (%d)\n", fwstatus.status); 136 | break; 137 | } 138 | ret = -1; 139 | } else if (fwstatus.status == WED_FWSTATUS_UPLOAD_READY) { 140 | 141 | int bRetry = 0; 142 | int bFinished = 0; 143 | int i, j; 144 | for (j = 0; j < g_fwup_speedup && !bFinished && !bRetry; ++j) 145 | { 146 | for (i = 0; i < WED_FW_STREAM_BLOCKS; ++i) { 147 | WEDFirmwareCommand fwdata; 148 | memset(&fwdata, 0, sizeof(fwdata)); 149 | fwdata.pkt_type = WED_FIRMWARE_DATA_BLOCK; 150 | long int offset = ftell(g_fwImageFile); 151 | size_t len = fread(fwdata.data, 1, WED_FW_BLOCK_SIZE, g_fwImageFile); 152 | if (len == 0) { 153 | bFinished = 1; 154 | if (g_opt.verbosity) 155 | printf("(ended)\n"); 156 | break; 157 | } 158 | if (len < WED_FW_BLOCK_SIZE) { 159 | bFinished = 1; 160 | printf("(uneven image size!)\n"); 161 | break; 162 | } 163 | g_fwImageWrittenSize += len; 164 | ret = exec_write(dev->sock, handle, (uint8_t *) &fwdata, sizeof(fwdata)); 165 | if (ret) 166 | { 167 | fseek(g_fwImageFile, offset, SEEK_SET); 168 | bRetry = 1; 169 | printf("(write retry)\n"); 170 | break; 171 | } 172 | if (feof(g_fwImageFile) || g_fwImageWrittenSize == g_fwImageSize) 173 | { 174 | bFinished = 1; 175 | break; 176 | } 177 | } // end for (i 178 | g_fwImageWrittenPage++; 179 | printf("\rUpdating ... %u/%u page %u/%u (%2.0f%%)", g_fwImageWrittenSize, g_fwImageSize, 180 | g_fwImageWrittenPage, g_fwImagePage, (g_fwImageWrittenSize * 100.0) / g_fwImageSize); 181 | fflush(stdout); 182 | usleep(100); 183 | } 184 | 185 | // Done uploding in our end 186 | if (bFinished) { 187 | printf(" (data done)"); 188 | WEDFirmwareCommand fwcmd; 189 | memset(&fwcmd, 0, sizeof(fwcmd)); 190 | fwcmd.pkt_type = WED_FIRMWARE_DATA_DONE; 191 | 192 | ret = exec_write(dev->sock, handle, (uint8_t *) &fwcmd, sizeof(fwcmd)); 193 | } 194 | fflush(stdout); 195 | 196 | ret = exec_read(dev->sock, handle); // Continue polling 197 | } else if (fwstatus.status == WED_FWSTATUS_UPDATE_READY) { 198 | if (g_fwImageWrittenSize != g_fwImageSize) { 199 | fprintf(stderr, " Update not ready!\n"); 200 | return -1; 201 | } 202 | WEDFirmwareCommand fwcmd; 203 | memset(&fwcmd, 0, sizeof(fwcmd)); 204 | fwcmd.pkt_type = WED_FIRMWARE_UPDATE; 205 | 206 | ret = exec_write(dev->sock, handle, (uint8_t *) &fwcmd, sizeof(fwcmd)); 207 | printf(" (Updating done)\n"); 208 | // Done with command 209 | dev->state = STATE_COUNT; 210 | } else { 211 | fprintf(stderr, "Unknown firmware update state (%u)\n", fwstatus.status); 212 | ret = -1; 213 | } 214 | return ret; 215 | } 216 | -------------------------------------------------------------------------------- /gapproto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GAP protocol using L2CAP sockets 3 | * 4 | * @date March 8, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #include "jni/bluetooth.h" 16 | #include "jni/hci.h" 17 | #include "jni/hci_lib.h" 18 | #include "jni/l2cap.h" 19 | #include "btio.h" 20 | #include "att.h" 21 | 22 | #include "common.h" 23 | #include "amidefs.h" 24 | 25 | size_t g_buflen; // Established MTU 26 | 27 | // Read a characteristic 28 | // Inputs: 29 | // sock - socket to perform operation on 30 | // handle - characteristics handle to read from 31 | int exec_read(int sock, uint16_t handle) { 32 | if (handle == 0) 33 | return -1; 34 | 35 | uint8_t * buf = malloc(g_buflen); 36 | memset(buf, 0, g_buflen); 37 | 38 | uint16_t plen = enc_read_req(handle, buf, g_buflen); 39 | 40 | ssize_t len = send(sock, buf, plen, 0); 41 | 42 | free(buf); 43 | if (len < 0 || len != plen) { 44 | return -1; 45 | } 46 | return 0; 47 | } 48 | 49 | // Write to a characteristic 50 | // Inputs: 51 | // sock - socket to perform operation on 52 | // handle - characteristics handle to write to 53 | // value - value to write 54 | // vlen - size of value in bytes 55 | int exec_write(int sock, uint16_t handle, const uint8_t * value, size_t vlen) { 56 | if (handle == 0) 57 | return -1; 58 | 59 | uint8_t * buf = malloc(g_buflen); 60 | memset(buf, 0, g_buflen); 61 | uint16_t plen = enc_write_cmd(handle, value, vlen, buf, g_buflen); 62 | 63 | ssize_t len = send(sock, buf, plen, 0); 64 | 65 | free(buf); 66 | if (len < 0 || len != plen) { 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | // Write to a characteristic with response 74 | // Inputs: 75 | // sock - socket to perform operation on 76 | // handle - characteristics handle to write to 77 | // value - value to write 78 | // vlen - size of value in bytes 79 | int exec_write_req(int sock, uint16_t handle, const uint8_t * value, size_t vlen) { 80 | if (handle == 0) 81 | return -1; 82 | 83 | uint8_t * buf = malloc(g_buflen); 84 | memset(buf, 0, g_buflen); 85 | uint16_t plen = enc_write_req(handle, value, vlen, buf, g_buflen); 86 | 87 | ssize_t len = send(sock, buf, plen, 0); 88 | 89 | free(buf); 90 | if (len < 0 || len != plen) { 91 | return -1; 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | // Find handle associated with given UUID 98 | int discover_handles(int sock, uint16_t start_handle, uint16_t end_handle) { 99 | uint16_t plen; 100 | bt_uuid_t type_uuid; 101 | 102 | uint8_t * buf = malloc(g_buflen); 103 | memset(buf, 0, g_buflen); 104 | 105 | bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID); 106 | 107 | plen = enc_read_by_type_req(start_handle, end_handle, &type_uuid, buf, 108 | g_buflen); 109 | 110 | ssize_t len = send(sock, buf, plen, 0); 111 | 112 | free(buf); 113 | if (len < 0 || len != plen) { 114 | return -1; 115 | } 116 | return 0; 117 | } 118 | 119 | // Connect and get GAP socket 120 | int gap_connect(const char * src, const char * dst) { 121 | int ret; 122 | struct set_opts opts; 123 | memset(&opts, 0, sizeof(opts)); 124 | 125 | if (dst == NULL || strlen(dst) == 0) { 126 | fprintf(stderr, 127 | "Device address must be specified (use --help to find the usage)\n"); 128 | return -1; 129 | } 130 | if (str2ba(dst, &opts.dst)) { 131 | fprintf(stderr, 132 | "Invalid device address (use --help to find the usage)!\n"); 133 | return -1; 134 | } 135 | 136 | if (src != NULL) { 137 | if (!strncmp(src, "hci", 3)) { 138 | ret = hci_devba(atoi(src + 3), &opts.src); 139 | if (ret == 0 && g_opt.verbosity) { 140 | char addr[18]; 141 | ba2str(&opts.src, addr); 142 | printf("Source address: %s\n", addr); 143 | } 144 | } else { 145 | ret = str2ba(src, &opts.src); 146 | } 147 | if (ret) { 148 | fprintf(stderr, 149 | "Invalid interface (use --help to find the usage)!\n"); 150 | return -1; 151 | } 152 | } else { 153 | bacpy(&opts.src, BDADDR_ANY); 154 | } 155 | opts.type = BT_IO_L2CAP; 156 | opts.src_type = BDADDR_LE_PUBLIC; 157 | opts.dst_type = BDADDR_LE_PUBLIC; 158 | opts.sec_level = BT_SECURITY_LOW; 159 | opts.master = -1; 160 | opts.flushable = -1; 161 | opts.mode = L2CAP_MODE_BASIC; 162 | opts.priority = 0; 163 | opts.cid = ATT_CID; 164 | 165 | int sock = bt_io_connect(&opts); 166 | if (sock <= 0) { 167 | fprintf(stderr, "bt_io_connect (%d)\n", errno); 168 | return -1; 169 | } 170 | { 171 | // Increase socket's receive buffer 172 | int opt_rcvbuf = (2 * 1024 * 1024); 173 | ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *) &opt_rcvbuf, sizeof(int)); 174 | if (ret) { 175 | fprintf(stderr, "setsockopt SO_RCVBUF (%d)\n", errno); 176 | return -1; 177 | } 178 | // Increase socket's send buffer 179 | int opt_sndbuf = (4 * 1024 * 1024); 180 | ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *) &opt_sndbuf, sizeof(int)); 181 | if (ret) { 182 | fprintf(stderr, "setsockopt SO_SNDBUF (%d)\n", errno); 183 | return -1; 184 | } 185 | } 186 | 187 | int ready; 188 | struct timeval tv; 189 | fd_set write_fds; 190 | tv.tv_sec = 5; 191 | tv.tv_usec = 0; 192 | FD_ZERO(&write_fds); 193 | FD_SET(sock, &write_fds); 194 | 195 | ready = select(sock + 1, NULL, &write_fds, NULL, &tv); 196 | if (!(ready > 0 && FD_ISSET(sock, &write_fds))) { 197 | fprintf(stderr, "Connection time out %d error (%d)\n", ready, errno); 198 | return -1; 199 | } 200 | { 201 | int soerr = 0; 202 | socklen_t olen = sizeof(soerr); 203 | if (getsockopt(sock, SOL_SOCKET , SO_ERROR, &soerr, &olen) < 0) 204 | { 205 | fprintf(stderr, "getsockopt() time out error (%d)\n", errno); 206 | return -1; 207 | } 208 | if (soerr) 209 | { 210 | fprintf(stderr, "Socket error %d error (%d)\n", soerr, errno); 211 | return -1; 212 | } 213 | // Clear errno 214 | errno = 0; 215 | } 216 | 217 | // Get the CID and MTU information 218 | bt_io_get(sock, BT_IO_OPT_OMTU, &opts.omtu, BT_IO_OPT_IMTU, &opts.imtu, 219 | BT_IO_OPT_CID, &opts.cid, BT_IO_OPT_INVALID); 220 | 221 | g_buflen = (opts.cid == ATT_CID) ? ATT_DEFAULT_LE_MTU : opts.imtu; 222 | 223 | printf("Session started ('q' to quit):\n\t" 224 | " SRC: %s OMTU: %d IMTU: %d CID: %d DST: %s\n\n", src, opts.omtu, opts.imtu, 225 | opts.cid, dst); 226 | 227 | return sock; 228 | } 229 | 230 | // Read data from gap socket 231 | int gap_recv(int sock, void * buf, size_t buflen) { 232 | struct timeval tv; 233 | tv.tv_sec = 0; 234 | tv.tv_usec = 10000; 235 | 236 | fd_set read_fds; 237 | FD_ZERO(&read_fds); 238 | FD_SET(sock, &read_fds); 239 | 240 | int ready = select(sock + 1, &read_fds, NULL, NULL, &tv); 241 | if (ready == -1) { 242 | fprintf(stderr, "main select() error\n"); 243 | return -1; 244 | } 245 | 246 | int len = 0; 247 | if (ready > 0 && FD_ISSET(sock, &read_fds)) { 248 | len = (int)recv(sock, buf, buflen, 0); 249 | if (len < 0) { 250 | if (errno == EAGAIN) { 251 | len = 0; 252 | } else { 253 | fprintf(stderr, "main recv() error (%d)\n", errno); 254 | return -1; 255 | } 256 | } 257 | } 258 | 259 | return len; 260 | } 261 | 262 | // Shutdown the socket 263 | int gap_shutdown(int sock) { 264 | if (sock < 0) 265 | return -1; 266 | 267 | // Close socket 268 | shutdown(sock, SHUT_RDWR); 269 | close(sock); 270 | 271 | return 0; 272 | } 273 | 274 | -------------------------------------------------------------------------------- /amproto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo low-level protocol 3 | * 4 | * @date March 8, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | * 8 | * @notes: 9 | * 10 | * this is not supposed to keep track of any state 11 | * just a low-level wrapper for gapproto 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "amidefs.h" 22 | #include "common.h" 23 | #include "gapproto.h" 24 | #include "amproto.h" 25 | #include "amchar.h" 26 | #include "amcmd.h" 27 | 28 | // Read the status (this is called also for keep-alive) 29 | int exec_status(int sock) { 30 | int ret; 31 | 32 | uint16_t handle = g_char[AMIIGO_UUID_STATUS].value_handle; 33 | if (handle == 0) 34 | return -1; // Not ready yet 35 | 36 | // Now read for status 37 | ret = exec_read(sock, handle); 38 | 39 | return ret; 40 | } 41 | 42 | // Read the extended status 43 | int exec_extstatus(int sock) { 44 | int ret; 45 | 46 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 47 | if (handle == 0) 48 | return -1; // Not ready yet 49 | 50 | // Now read for status 51 | ret = exec_read(sock, handle); 52 | 53 | return ret; 54 | } 55 | 56 | // Start firmware update procedure 57 | int exec_fwupdate(int sock) { 58 | int ret; 59 | 60 | uint16_t handle = g_char[AMIIGO_UUID_FIRMWARE].value_handle; 61 | if (handle == 0) 62 | return -1; // Not ready yet 63 | 64 | printf("\nPreparing for update ...\n"); 65 | 66 | // Now read for status 67 | ret = exec_read(sock, handle); 68 | 69 | return ret; 70 | } 71 | 72 | // Debug i2c by reading or writing register on given address 73 | int exec_debug_i2c(int sock) { 74 | int ret; 75 | 76 | uint16_t handle = g_char[AMIIGO_UUID_DEBUG].value_handle; 77 | if (handle == 0) 78 | return -1; // Not ready yet 79 | 80 | ret = exec_write(sock, handle, (uint8_t *) &g_cfg.i2c, sizeof(g_cfg.i2c)); 81 | if (ret) 82 | return -1; 83 | 84 | // Wait for it a little 85 | usleep(100); 86 | ret = exec_read(sock, handle); 87 | 88 | return ret; 89 | } 90 | 91 | // Start downloading the log packets 92 | int exec_download(int sock) { 93 | 94 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 95 | if (handle == 0) 96 | return -1; // Not ready yet 97 | printf("\n\n"); 98 | // Config for notify 99 | WEDConfig config; 100 | memset(&config, 0, sizeof(config)); 101 | config.config_type = WED_CFG_LOG; 102 | if (g_opt.raw) 103 | config.log.flags = WED_CONFIG_LOG_DL_EN; 104 | else 105 | config.log.flags = WED_CONFIG_LOG_DL_EN | WED_CONFIG_LOG_CMP_EN; 106 | if (g_opt.live) 107 | config.log.flags |= WED_CONFIG_LOG_LOOPBACK; 108 | 109 | 110 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.log)); 111 | if (ret) 112 | return -1; 113 | 114 | return 0; 115 | } 116 | 117 | // Start configuration of light sensors 118 | int exec_configls(int sock) { 119 | 120 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 121 | if (handle == 0) 122 | return -1; // Not ready yet 123 | 124 | WEDConfig config; 125 | memset(&config, 0, sizeof(config)); 126 | config.config_type = WED_CFG_LS; 127 | config.lightsensor = g_cfg.config_ls; 128 | 129 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.lightsensor)); 130 | if (ret) 131 | return -1; 132 | 133 | return 0; 134 | } 135 | 136 | // Start configuration of temperature sensor 137 | int exec_configtemp(int sock) { 138 | 139 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 140 | if (handle == 0) 141 | return -1; // Not ready yet 142 | 143 | WEDConfig config; 144 | memset(&config, 0, sizeof(config)); 145 | config.config_type = WED_CFG_TEMP; 146 | config.temp = g_cfg.config_temp; 147 | 148 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.accel)); 149 | if (ret) 150 | return -1; 151 | 152 | return 0; 153 | } 154 | 155 | // Start configuration of accel sensors 156 | int exec_configaccel(int sock) { 157 | 158 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 159 | if (handle == 0) 160 | return -1; // Not ready yet 161 | 162 | WEDConfig config; 163 | memset(&config, 0, sizeof(config)); 164 | config.config_type = WED_CFG_ACCEL; 165 | config.accel = g_cfg.config_accel; 166 | 167 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.accel)); 168 | if (ret) 169 | return -1; 170 | 171 | return 0; 172 | } 173 | 174 | // Switch accel log sequence mode (testing mode log accel count instead of accel values) 175 | int exec_test_seq(int sock) { 176 | 177 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 178 | if (handle == 0) 179 | return -1; // Not ready yet 180 | 181 | WEDConfigMaint config_maint; 182 | memset(&config_maint, 0, sizeof(config_maint)); 183 | config_maint.command = WED_TEST_SEQUENCE; 184 | config_maint.mode = g_cfg.test_mode; 185 | WEDConfig config; 186 | memset(&config, 0, sizeof(config)); 187 | config.config_type = WED_CFG_MAINT; 188 | config.maint = config_maint; 189 | 190 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.maint)); 191 | if (ret) 192 | return -1; 193 | 194 | return 0; 195 | } 196 | 197 | // Start LED blinking 198 | int exec_blink(int sock) { 199 | 200 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 201 | if (handle == 0) 202 | return -1; // Not ready yet 203 | 204 | WEDConfigMaint config_maint; 205 | memset(&config_maint, 0, sizeof(config_maint)); 206 | config_maint.command = WED_MAINT_BLINK_LED; 207 | config_maint.led = g_cfg.maint_led; 208 | WEDConfig config; 209 | memset(&config, 0, sizeof(config)); 210 | config.config_type = WED_CFG_MAINT; 211 | config.maint = config_maint; 212 | 213 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.maint)); 214 | if (ret) 215 | return -1; 216 | 217 | return 0; 218 | } 219 | 220 | // Go to deep sleep until hard double tap 221 | int exec_deepsleep(int sock) { 222 | 223 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 224 | if (handle == 0) 225 | return -1; // Not ready yet 226 | 227 | WEDConfigMaint config_maint; 228 | memset(&config_maint, 0, sizeof(config_maint)); 229 | config_maint.command = WED_DEEP_SLEEP; 230 | WEDConfig config; 231 | memset(&config, 0, sizeof(config)); 232 | config.config_type = WED_CFG_MAINT; 233 | config.maint = config_maint; 234 | 235 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.maint)); 236 | if (ret) 237 | return -1; 238 | 239 | return 0; 240 | } 241 | 242 | // Start LED blinking 243 | int exec_tag(int sock) { 244 | 245 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 246 | if (handle == 0) 247 | return -1; // Not ready yet 248 | 249 | WEDConfig config; 250 | memset(&config, 0, sizeof(config)); 251 | config.config_type = WED_CFG_GENERAL; 252 | config.general = g_cfg.general; 253 | config.general.flags |= (CFG_WRITE_TAG | CFG_FLUSH_LOG); 254 | 255 | uint32_t tag; 256 | memcpy(&tag, &config.general.tag[0], 4); 257 | // Override if 0 to the most recent time 258 | if (tag == 0) { 259 | tag = (uint32_t)(time(NULL) & 0xFFFFFFFF); 260 | memcpy(&config.general.tag[0], &tag, 4); 261 | printf("Time tag %u\n", tag); 262 | } 263 | 264 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.general)); 265 | if (ret) 266 | return -1; 267 | 268 | return 0; 269 | } 270 | 271 | // Rename the WED 272 | int exec_rename(int sock) { 273 | 274 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 275 | if (handle == 0) 276 | return -1; // Not ready yet 277 | 278 | WEDConfig config; 279 | memset(&config, 0, sizeof(config)); 280 | config.config_type = WED_CFG_NAME; 281 | config.name = g_cfg.name; 282 | 283 | // Path with spaces 284 | int i; 285 | for (i = strlen(config.name.name); i < DEV_NAME_LEN; ++i) 286 | config.name.name[i] = ' '; 287 | 288 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.name)); 289 | if (ret) 290 | return -1; 291 | 292 | return 0; 293 | } 294 | 295 | // Reset config, or CPU or log buffer 296 | int exec_reset(int sock, AMIIGO_CMD cmd) { 297 | 298 | uint16_t handle = g_char[AMIIGO_UUID_CONFIG].value_handle; 299 | if (handle == 0) 300 | return -1; // Not ready yet 301 | WEDConfigMaint config_maint; 302 | memset(&config_maint, 0, sizeof(config_maint)); 303 | switch (cmd) { 304 | case AMIIGO_CMD_RESET_CPU: 305 | printf("Restarting the device ...\n"); 306 | config_maint.command = WED_MAINT_RESET; 307 | break; 308 | case AMIIGO_CMD_RESET_LOGS: 309 | printf("Clearing the logs ...\n"); 310 | config_maint.command = WED_MAINT_CLEAR_LOG; 311 | break; 312 | case AMIIGO_CMD_RESET_CONFIGS: 313 | printf("Reseting the configurations to default ...\n"); 314 | config_maint.command = WED_MAINT_RESET_CONFIG; 315 | break; 316 | default: 317 | return -1; 318 | break; 319 | } 320 | WEDConfig config; 321 | memset(&config, 0, sizeof(config)); 322 | config.config_type = WED_CFG_MAINT; 323 | config.maint = config_maint; 324 | 325 | int ret = exec_write(sock, handle, (uint8_t *) &config, sizeof(config.config_type) + sizeof(config.maint)); 326 | if (ret) 327 | return -1; 328 | 329 | return 0; 330 | } 331 | 332 | -------------------------------------------------------------------------------- /hcitool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hcitool.c 3 | * 4 | * modified from tool of the same name 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "jni/bluetooth.h" 14 | #include "jni/hci.h" 15 | #include "jni/hci_lib.h" 16 | 17 | #include "hcitool.h" 18 | #include "amlprocess.h" 19 | extern char g_src[512]; 20 | 21 | static volatile int signal_received = 0; 22 | 23 | #define FLAGS_AD_TYPE 0x01 24 | #define FLAGS_LIMITED_MODE_BIT 0x01 25 | #define FLAGS_GENERAL_MODE_BIT 0x02 26 | 27 | #define EIR_FLAGS 0x01 /* flags */ 28 | #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ 29 | #define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ 30 | #define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ 31 | #define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ 32 | #define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ 33 | #define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ 34 | #define EIR_NAME_SHORT 0x08 /* shortened local name */ 35 | #define EIR_NAME_COMPLETE 0x09 /* complete local name */ 36 | #define EIR_TX_POWER 0x0A /* transmit power level */ 37 | #define EIR_DEVICE_ID 0x10 /* device ID */ 38 | 39 | static void sigint_handler(int sig) { 40 | signal_received = sig; 41 | } 42 | 43 | static int read_flags(uint8_t *flags, const uint8_t *data, size_t size) { 44 | size_t offset; 45 | 46 | if (!flags || !data) 47 | return -EINVAL; 48 | 49 | offset = 0; 50 | while (offset < size) { 51 | uint8_t len = data[offset]; 52 | uint8_t type; 53 | 54 | /* Check if it is the end of the significant part */ 55 | if (len == 0) 56 | break; 57 | 58 | if (len + offset > size) 59 | break; 60 | 61 | type = data[offset + 1]; 62 | 63 | if (type == FLAGS_AD_TYPE) { 64 | *flags = data[offset + 2]; 65 | return 0; 66 | } 67 | 68 | offset += 1 + len; 69 | } 70 | 71 | return -ENOENT; 72 | } 73 | 74 | static int check_report_filter(uint8_t procedure, le_advertising_info *info) { 75 | uint8_t flags; 76 | 77 | /* If no discovery procedure is set, all reports are treat as valid */ 78 | if (procedure == 0) 79 | return 1; 80 | 81 | /* Read flags AD type value from the advertising report if it exists */ 82 | if (read_flags(&flags, info->data, info->length)) 83 | return 0; 84 | 85 | switch (procedure) { 86 | case 'l': /* Limited Discovery Procedure */ 87 | if (flags & FLAGS_LIMITED_MODE_BIT) 88 | return 1; 89 | break; 90 | case 'g': /* General Discovery Procedure */ 91 | if (flags & (FLAGS_LIMITED_MODE_BIT | FLAGS_GENERAL_MODE_BIT)) 92 | return 1; 93 | break; 94 | default: 95 | fprintf(stderr, "Unknown discovery procedure\n"); 96 | } 97 | 98 | return 0; 99 | } 100 | 101 | static void eir_parse_name(uint8_t *eir, size_t eir_len, char *buf, 102 | size_t buf_len) { 103 | size_t offset = 0; 104 | 105 | while (offset < eir_len) { 106 | uint8_t field_len = eir[0]; 107 | size_t name_len; 108 | 109 | /* Check for the end of EIR */ 110 | if (field_len == 0) 111 | break; 112 | 113 | if (offset + field_len > eir_len) 114 | goto failed; 115 | 116 | switch (eir[1]) { 117 | case EIR_NAME_SHORT: 118 | case EIR_NAME_COMPLETE: 119 | name_len = field_len - 1; 120 | if (name_len > buf_len) 121 | name_len = buf_len - 1; 122 | 123 | memcpy(buf, &eir[2], name_len); 124 | return; 125 | } 126 | 127 | offset += field_len + 1; 128 | eir += field_len + 1; 129 | } 130 | 131 | failed: snprintf(buf, buf_len, "(unknown)"); 132 | } 133 | 134 | static void eir_parse_uuid(uint8_t *eir, size_t eir_len, char *buf, 135 | size_t buf_len) { 136 | size_t offset = 0; 137 | 138 | while (offset < eir_len) { 139 | uint8_t field_len = eir[0]; 140 | size_t uuid_len; 141 | 142 | /* Check for the end of EIR */ 143 | if (field_len == 0) 144 | break; 145 | 146 | if (offset + field_len > eir_len) 147 | goto failed; 148 | 149 | switch (eir[1]) { 150 | case EIR_UUID128_ALL: 151 | uuid_len = field_len - 1; 152 | if (uuid_len != 16 || buf_len < 2 * uuid_len) 153 | goto failed; 154 | uint8_t * ba = &eir[2]; 155 | sprintf(buf, "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", 156 | ba[15], ba[14], ba[13], ba[12], ba[11], ba[10], ba[9], ba[8], ba[7], ba[6], ba[5], ba[4], ba[3], ba[2], ba[1], ba[0]); 157 | return; 158 | } 159 | 160 | offset += field_len + 1; 161 | eir += field_len + 1; 162 | } 163 | 164 | failed: 165 | memset(buf, 0, buf_len); 166 | } 167 | 168 | static void eir_parse_amiigo(uint8_t *eir, size_t eir_len) { 169 | size_t offset = 0; 170 | 171 | while (offset < eir_len) { 172 | uint8_t field_len = eir[0]; 173 | uint8_t mfgr_len; 174 | 175 | /* Check for the end of EIR */ 176 | if (field_len == 0) 177 | break; 178 | 179 | if (offset + field_len > eir_len) 180 | break; 181 | 182 | switch (eir[1]) { 183 | case 0xFF: 184 | mfgr_len = field_len - 1; 185 | uint8_t * ba = &eir[2]; 186 | if (mfgr_len > 5) 187 | printf("%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", ba[0], ba[1], ba[2], ba[3], ba[4], ba[5]); 188 | if (mfgr_len > 6) 189 | print_status(ba[6]); 190 | if (mfgr_len > 7) 191 | printf(" (test %d %s) ", ba[7], ba[7] ? "failed" : "passed"); 192 | return; 193 | } 194 | 195 | offset += field_len + 1; 196 | eir += field_len + 1; 197 | } 198 | } 199 | 200 | static int print_advertising_devices(int dd, uint8_t filter_type) { 201 | unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr; 202 | struct hci_filter nf, of; 203 | struct sigaction sa; 204 | socklen_t olen; 205 | int len; 206 | 207 | olen = sizeof(of); 208 | if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) { 209 | printf("Could not get socket options\n"); 210 | return -1; 211 | } 212 | 213 | hci_filter_clear(&nf); 214 | hci_filter_set_ptype(HCI_EVENT_PKT, &nf); 215 | hci_filter_set_event(EVT_LE_META_EVENT, &nf); 216 | 217 | if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) { 218 | printf("Could not set socket options\n"); 219 | return -1; 220 | } 221 | 222 | memset(&sa, 0, sizeof(sa)); 223 | sa.sa_flags = SA_NOCLDSTOP; 224 | sa.sa_handler = sigint_handler; 225 | sigaction(SIGINT, &sa, NULL); 226 | 227 | while (1) { 228 | evt_le_meta_event *meta; 229 | le_advertising_info *info; 230 | char addr[18]; 231 | 232 | while ((len = read(dd, buf, sizeof(buf))) < 0) { 233 | if (errno == EINTR && signal_received == SIGINT) { 234 | len = 0; 235 | goto done; 236 | } 237 | 238 | if (errno == EAGAIN || errno == EINTR) 239 | continue; 240 | goto done; 241 | } 242 | 243 | ptr = buf + (1 + HCI_EVENT_HDR_SIZE); 244 | len -= (1 + HCI_EVENT_HDR_SIZE); 245 | 246 | meta = (void *) ptr; 247 | 248 | if (meta->subevent != 0x02) 249 | goto done; 250 | 251 | /* Ignoring multiple reports */ 252 | info = (le_advertising_info *) (meta->data + 1); 253 | if (check_report_filter(filter_type, info)) { 254 | char name[30]; 255 | char uuid[16*2 + 1]; 256 | 257 | memset(name, 0, sizeof(name)); 258 | 259 | ba2str(&info->bdaddr, addr); 260 | eir_parse_name(info->data, info->length, name, sizeof(name) - 1); 261 | eir_parse_uuid(info->data, info->length, uuid, sizeof(uuid) - 1); 262 | 263 | printf("%s %s %s", addr, name, uuid); 264 | 265 | if (strcmp(uuid, "CCA3100078C647859E450887D451317C") == 0) { 266 | printf(" Amiigo "); 267 | eir_parse_amiigo(info->data, info->length); 268 | } 269 | 270 | printf("\n"); 271 | } 272 | } 273 | 274 | done: setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of)); 275 | 276 | if (len < 0) 277 | return -1; 278 | 279 | return 0; 280 | } 281 | 282 | int do_lescan() { 283 | int dev_id, sock; 284 | int ret; 285 | 286 | if (!strncmp(g_src, "hci", 3)) { 287 | dev_id = atoi(g_src + 3); 288 | } else { 289 | fprintf(stderr, "Adapter %s is unknown, using the default\n", g_src); 290 | dev_id = hci_get_route(NULL); 291 | } 292 | sock = hci_open_dev(dev_id); 293 | if (dev_id < 0 || sock < 0) { 294 | perror("opening socket"); 295 | exit(1); 296 | } 297 | 298 | uint8_t own_type = 0x00; 299 | uint16_t interval = htobs(0x0012); 300 | uint16_t window = htobs(0x0012); 301 | uint8_t scan_type = 0x01; 302 | uint8_t filter_dup = 1; 303 | uint8_t filter_type = 0; 304 | ret = hci_le_set_scan_parameters(sock, scan_type, interval, window, 305 | own_type, 0x00, 1000); 306 | if (ret) { 307 | perror("hci_le_set_scan_parameters"); 308 | exit(1); 309 | } 310 | 311 | ret = hci_le_set_scan_enable(sock, 0x01, filter_dup, 1000); 312 | if (ret) { 313 | perror("hci_le_set_scan_enable"); 314 | exit(1); 315 | } 316 | 317 | print_advertising_devices(sock, filter_type); 318 | 319 | ret = hci_le_set_scan_enable(sock, 0x00, filter_dup, 1000); 320 | 321 | close(sock); 322 | return 0; 323 | } 324 | 325 | -------------------------------------------------------------------------------- /jni/hci_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2000-2001 Qualcomm Incorporated 6 | * Copyright (C) 2002-2003 Maxim Krasnyansky 7 | * Copyright (C) 2002-2010 Marcel Holtmann 8 | * 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifndef __HCI_LIB_H 27 | #define __HCI_LIB_H 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | struct hci_request { 34 | uint16_t ogf; 35 | uint16_t ocf; 36 | int event; 37 | void *cparam; 38 | int clen; 39 | void *rparam; 40 | int rlen; 41 | }; 42 | 43 | struct hci_version { 44 | uint16_t manufacturer; 45 | uint8_t hci_ver; 46 | uint16_t hci_rev; 47 | uint8_t lmp_ver; 48 | uint16_t lmp_subver; 49 | }; 50 | 51 | int hci_open_dev(int dev_id); 52 | int hci_close_dev(int dd); 53 | int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param); 54 | int hci_send_req(int dd, struct hci_request *req, int timeout); 55 | 56 | int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to); 57 | int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to); 58 | 59 | int hci_inquiry(int dev_id, int len, int num_rsp, const uint8_t *lap, inquiry_info **ii, long flags); 60 | int hci_devinfo(int dev_id, struct hci_dev_info *di); 61 | int hci_devba(int dev_id, bdaddr_t *bdaddr); 62 | int hci_devid(const char *str); 63 | 64 | int hci_read_local_name(int dd, int len, char *name, int to); 65 | int hci_write_local_name(int dd, const char *name, int to); 66 | int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to); 67 | int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to); 68 | int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to); 69 | int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to); 70 | int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to); 71 | int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to); 72 | int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to); 73 | int hci_read_local_version(int dd, struct hci_version *ver, int to); 74 | int hci_read_local_commands(int dd, uint8_t *commands, int to); 75 | int hci_read_local_features(int dd, uint8_t *features, int to); 76 | int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to); 77 | int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to); 78 | int hci_read_class_of_dev(int dd, uint8_t *cls, int to); 79 | int hci_write_class_of_dev(int dd, uint32_t cls, int to); 80 | int hci_read_voice_setting(int dd, uint16_t *vs, int to); 81 | int hci_write_voice_setting(int dd, uint16_t vs, int to); 82 | int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to); 83 | int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to); 84 | int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to); 85 | int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to); 86 | int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to); 87 | int hci_authenticate_link(int dd, uint16_t handle, int to); 88 | int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to); 89 | int hci_change_link_key(int dd, uint16_t handle, int to); 90 | int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to); 91 | int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to); 92 | int hci_exit_park_mode(int dd, uint16_t handle, int to); 93 | int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to); 94 | int hci_write_inquiry_scan_type(int dd, uint8_t type, int to); 95 | int hci_read_inquiry_mode(int dd, uint8_t *mode, int to); 96 | int hci_write_inquiry_mode(int dd, uint8_t mode, int to); 97 | int hci_read_afh_mode(int dd, uint8_t *mode, int to); 98 | int hci_write_afh_mode(int dd, uint8_t mode, int to); 99 | int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to); 100 | int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to); 101 | int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to); 102 | int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to); 103 | int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to); 104 | int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to); 105 | int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to); 106 | int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to); 107 | int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to); 108 | int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to); 109 | int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to); 110 | int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to); 111 | int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to); 112 | int hci_set_afh_classification(int dd, uint8_t *map, int to); 113 | int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to); 114 | int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to); 115 | int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to); 116 | int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to); 117 | 118 | int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup, int to); 119 | int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval, 120 | uint16_t window, uint8_t own_type, 121 | uint8_t filter, int to); 122 | int hci_le_set_advertise_enable(int dev_id, uint8_t enable, int to); 123 | int hci_le_create_conn(int dd, uint16_t interval, uint16_t window, 124 | uint8_t initiator_filter, uint8_t peer_bdaddr_type, 125 | bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type, 126 | uint16_t min_interval, uint16_t max_interval, 127 | uint16_t latency, uint16_t supervision_timeout, 128 | uint16_t min_ce_length, uint16_t max_ce_length, 129 | uint16_t *handle, int to); 130 | 131 | int hci_le_conn_update(int dd, uint16_t handle, uint16_t min_interval, 132 | uint16_t max_interval, uint16_t latency, 133 | uint16_t supervision_timeout, int to); 134 | int hci_le_add_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to); 135 | int hci_le_rm_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to); 136 | int hci_le_read_white_list_size(int dd, uint8_t *size, int to); 137 | int hci_le_clear_white_list(int dd, int to); 138 | int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg); 139 | int hci_get_route(bdaddr_t *bdaddr); 140 | 141 | char *hci_bustostr(int bus); 142 | char *hci_typetostr(int type); 143 | char *hci_dtypetostr(int type); 144 | char *hci_dflagstostr(uint32_t flags); 145 | char *hci_ptypetostr(unsigned int ptype); 146 | int hci_strtoptype(char *str, unsigned int *val); 147 | char *hci_scoptypetostr(unsigned int ptype); 148 | int hci_strtoscoptype(char *str, unsigned int *val); 149 | char *hci_lptostr(unsigned int ptype); 150 | int hci_strtolp(char *str, unsigned int *val); 151 | char *hci_lmtostr(unsigned int ptype); 152 | int hci_strtolm(char *str, unsigned int *val); 153 | 154 | char *hci_cmdtostr(unsigned int cmd); 155 | char *hci_commandstostr(uint8_t *commands, char *pref, int width); 156 | 157 | char *hci_vertostr(unsigned int ver); 158 | int hci_strtover(char *str, unsigned int *ver); 159 | char *lmp_vertostr(unsigned int ver); 160 | int lmp_strtover(char *str, unsigned int *ver); 161 | 162 | char *lmp_featurestostr(uint8_t *features, char *pref, int width); 163 | 164 | static inline void hci_set_bit(int nr, void *addr) 165 | { 166 | *((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31)); 167 | } 168 | 169 | static inline void hci_clear_bit(int nr, void *addr) 170 | { 171 | *((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31)); 172 | } 173 | 174 | static inline int hci_test_bit(int nr, void *addr) 175 | { 176 | return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31)); 177 | } 178 | 179 | /* HCI filter tools */ 180 | static inline void hci_filter_clear(struct hci_filter *f) 181 | { 182 | memset(f, 0, sizeof(*f)); 183 | } 184 | static inline void hci_filter_set_ptype(int t, struct hci_filter *f) 185 | { 186 | hci_set_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); 187 | } 188 | static inline void hci_filter_clear_ptype(int t, struct hci_filter *f) 189 | { 190 | hci_clear_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); 191 | } 192 | static inline int hci_filter_test_ptype(int t, struct hci_filter *f) 193 | { 194 | return hci_test_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask); 195 | } 196 | static inline void hci_filter_all_ptypes(struct hci_filter *f) 197 | { 198 | memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask)); 199 | } 200 | static inline void hci_filter_set_event(int e, struct hci_filter *f) 201 | { 202 | hci_set_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); 203 | } 204 | static inline void hci_filter_clear_event(int e, struct hci_filter *f) 205 | { 206 | hci_clear_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); 207 | } 208 | static inline int hci_filter_test_event(int e, struct hci_filter *f) 209 | { 210 | return hci_test_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask); 211 | } 212 | static inline void hci_filter_all_events(struct hci_filter *f) 213 | { 214 | memset((void *) f->event_mask, 0xff, sizeof(f->event_mask)); 215 | } 216 | static inline void hci_filter_set_opcode(int opcode, struct hci_filter *f) 217 | { 218 | f->opcode = opcode; 219 | } 220 | static inline void hci_filter_clear_opcode(struct hci_filter *f) 221 | { 222 | f->opcode = 0; 223 | } 224 | static inline int hci_filter_test_opcode(int opcode, struct hci_filter *f) 225 | { 226 | return (f->opcode == opcode); 227 | } 228 | 229 | #ifdef __cplusplus 230 | } 231 | #endif 232 | 233 | #endif /* __HCI_LIB_H */ 234 | -------------------------------------------------------------------------------- /jni/bluetooth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2000-2001 Qualcomm Incorporated 6 | * Copyright (C) 2002-2003 Maxim Krasnyansky 7 | * Copyright (C) 2002-2010 Marcel Holtmann 8 | * 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifndef __BLUETOOTH_H 27 | #define __BLUETOOTH_H 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifndef AF_BLUETOOTH 41 | #define AF_BLUETOOTH 31 42 | #define PF_BLUETOOTH AF_BLUETOOTH 43 | #endif 44 | 45 | #define BTPROTO_L2CAP 0 46 | #define BTPROTO_HCI 1 47 | #define BTPROTO_SCO 2 48 | #define BTPROTO_RFCOMM 3 49 | #define BTPROTO_BNEP 4 50 | #define BTPROTO_CMTP 5 51 | #define BTPROTO_HIDP 6 52 | #define BTPROTO_AVDTP 7 53 | 54 | #define SOL_HCI 0 55 | #define SOL_L2CAP 6 56 | #define SOL_SCO 17 57 | #define SOL_RFCOMM 18 58 | 59 | #ifndef SOL_BLUETOOTH 60 | #define SOL_BLUETOOTH 274 61 | #endif 62 | 63 | #define BT_SECURITY 4 64 | struct bt_security { 65 | uint8_t level; 66 | uint8_t key_size; 67 | }; 68 | #define BT_SECURITY_SDP 0 69 | #define BT_SECURITY_LOW 1 70 | #define BT_SECURITY_MEDIUM 2 71 | #define BT_SECURITY_HIGH 3 72 | 73 | #define BT_DEFER_SETUP 7 74 | 75 | #define BT_FLUSHABLE 8 76 | 77 | #define BT_FLUSHABLE_OFF 0 78 | #define BT_FLUSHABLE_ON 1 79 | 80 | #define BT_CHANNEL_POLICY 10 81 | 82 | /* BR/EDR only (default policy) 83 | * AMP controllers cannot be used. 84 | * Channel move requests from the remote device are denied. 85 | * If the L2CAP channel is currently using AMP, move the channel to BR/EDR. 86 | */ 87 | #define BT_CHANNEL_POLICY_BREDR_ONLY 0 88 | 89 | /* BR/EDR Preferred 90 | * Allow use of AMP controllers. 91 | * If the L2CAP channel is currently on AMP, move it to BR/EDR. 92 | * Channel move requests from the remote device are allowed. 93 | */ 94 | #define BT_CHANNEL_POLICY_BREDR_PREFERRED 1 95 | 96 | /* AMP Preferred 97 | * Allow use of AMP controllers 98 | * If the L2CAP channel is currently on BR/EDR and AMP controller 99 | * resources are available, initiate a channel move to AMP. 100 | * Channel move requests from the remote device are allowed. 101 | * If the L2CAP socket has not been connected yet, try to create 102 | * and configure the channel directly on an AMP controller rather 103 | * than BR/EDR. 104 | */ 105 | #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 106 | 107 | #define BT_VOICE 11 108 | struct bt_voice { 109 | uint16_t setting; 110 | }; 111 | 112 | #define BT_VOICE_TRANSPARENT 0x0003 113 | #define BT_VOICE_CVSD_16BIT 0x0060 114 | 115 | /* Connection and socket states */ 116 | enum { 117 | BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ 118 | BT_OPEN, 119 | BT_BOUND, 120 | BT_LISTEN, 121 | BT_CONNECT, 122 | BT_CONNECT2, 123 | BT_CONFIG, 124 | BT_DISCONN, 125 | BT_CLOSED 126 | }; 127 | 128 | /* Byte order conversions */ 129 | #if __BYTE_ORDER == __LITTLE_ENDIAN 130 | #define htobs(d) (d) 131 | #define htobl(d) (d) 132 | #define htobll(d) (d) 133 | #define btohs(d) (d) 134 | #define btohl(d) (d) 135 | #define btohll(d) (d) 136 | #elif __BYTE_ORDER == __BIG_ENDIAN 137 | #define htobs(d) bswap_16(d) 138 | #define htobl(d) bswap_32(d) 139 | #define htobll(d) bswap_64(d) 140 | #define btohs(d) bswap_16(d) 141 | #define btohl(d) bswap_32(d) 142 | #define btohll(d) bswap_64(d) 143 | #else 144 | #error "Unknown byte order" 145 | #endif 146 | 147 | /* Bluetooth unaligned access */ 148 | #define bt_get_unaligned(ptr) \ 149 | ({ \ 150 | struct __attribute__((packed)) { \ 151 | typeof(*(ptr)) __v; \ 152 | } *__p = (typeof(__p)) (ptr); \ 153 | __p->__v; \ 154 | }) 155 | 156 | #define bt_put_unaligned(val, ptr) \ 157 | do { \ 158 | struct __attribute__((packed)) { \ 159 | typeof(*(ptr)) __v; \ 160 | } *__p = (typeof(__p)) (ptr); \ 161 | __p->__v = (val); \ 162 | } while(0) 163 | 164 | #if __BYTE_ORDER == __LITTLE_ENDIAN 165 | static inline uint64_t bt_get_le64(const void *ptr) 166 | { 167 | return bt_get_unaligned((const uint64_t *) ptr); 168 | } 169 | 170 | static inline uint64_t bt_get_be64(const void *ptr) 171 | { 172 | return bswap_64(bt_get_unaligned((const uint64_t *) ptr)); 173 | } 174 | 175 | static inline uint32_t bt_get_le32(const void *ptr) 176 | { 177 | return bt_get_unaligned((const uint32_t *) ptr); 178 | } 179 | 180 | static inline uint32_t bt_get_be32(const void *ptr) 181 | { 182 | return bswap_32(bt_get_unaligned((const uint32_t *) ptr)); 183 | } 184 | 185 | static inline uint16_t bt_get_le16(const void *ptr) 186 | { 187 | return bt_get_unaligned((const uint16_t *) ptr); 188 | } 189 | 190 | static inline uint16_t bt_get_be16(const void *ptr) 191 | { 192 | return bswap_16(bt_get_unaligned((const uint16_t *) ptr)); 193 | } 194 | 195 | static inline void bt_put_le64(uint64_t val, const void *ptr) 196 | { 197 | bt_put_unaligned(val, (uint64_t *) ptr); 198 | } 199 | 200 | static inline void bt_put_be64(uint64_t val, const void *ptr) 201 | { 202 | bt_put_unaligned(bswap_64(val), (uint64_t *) ptr); 203 | } 204 | 205 | static inline void bt_put_le32(uint32_t val, const void *ptr) 206 | { 207 | bt_put_unaligned(val, (uint32_t *) ptr); 208 | } 209 | 210 | static inline void bt_put_be32(uint32_t val, const void *ptr) 211 | { 212 | bt_put_unaligned(bswap_32(val), (uint32_t *) ptr); 213 | } 214 | 215 | static inline void bt_put_le16(uint16_t val, const void *ptr) 216 | { 217 | bt_put_unaligned(val, (uint16_t *) ptr); 218 | } 219 | 220 | static inline void bt_put_be16(uint16_t val, const void *ptr) 221 | { 222 | bt_put_unaligned(bswap_16(val), (uint16_t *) ptr); 223 | } 224 | 225 | #elif __BYTE_ORDER == __BIG_ENDIAN 226 | static inline uint64_t bt_get_le64(const void *ptr) 227 | { 228 | return bswap_64(bt_get_unaligned((const uint64_t *) ptr)); 229 | } 230 | 231 | static inline uint64_t bt_get_be64(const void *ptr) 232 | { 233 | return bt_get_unaligned((const uint64_t *) ptr); 234 | } 235 | 236 | static inline uint32_t bt_get_le32(const void *ptr) 237 | { 238 | return bswap_32(bt_get_unaligned((const uint32_t *) ptr)); 239 | } 240 | 241 | static inline uint32_t bt_get_be32(const void *ptr) 242 | { 243 | return bt_get_unaligned((const uint32_t *) ptr); 244 | } 245 | 246 | static inline uint16_t bt_get_le16(const void *ptr) 247 | { 248 | return bswap_16(bt_get_unaligned((const uint16_t *) ptr)); 249 | } 250 | 251 | static inline uint16_t bt_get_be16(const void *ptr) 252 | { 253 | return bt_get_unaligned((const uint16_t *) ptr); 254 | } 255 | 256 | static inline void bt_put_le64(uint64_t val, const void *ptr) 257 | { 258 | bt_put_unaligned(bswap_64(val), (uint64_t *) ptr); 259 | } 260 | 261 | static inline void bt_put_be64(uint64_t val, const void *ptr) 262 | { 263 | bt_put_unaligned(val, (uint64_t *) ptr); 264 | } 265 | 266 | static inline void bt_put_le32(uint32_t val, const void *ptr) 267 | { 268 | bt_put_unaligned(bswap_32(val), (uint32_t *) ptr); 269 | } 270 | 271 | static inline void bt_put_be32(uint32_t val, const void *ptr) 272 | { 273 | bt_put_unaligned(val, (uint32_t *) ptr); 274 | } 275 | 276 | static inline void bt_put_le16(uint16_t val, const void *ptr) 277 | { 278 | bt_put_unaligned(bswap_16(val), (uint16_t *) ptr); 279 | } 280 | 281 | static inline void bt_put_be16(uint16_t val, const void *ptr) 282 | { 283 | bt_put_unaligned(val, (uint16_t *) ptr); 284 | } 285 | #else 286 | #error "Unknown byte order" 287 | #endif 288 | 289 | /* BD Address */ 290 | typedef struct { 291 | uint8_t b[6]; 292 | } __attribute__((packed)) bdaddr_t; 293 | 294 | /* BD Address type */ 295 | #define BDADDR_BREDR 0x00 296 | #define BDADDR_LE_PUBLIC 0x01 297 | #define BDADDR_LE_RANDOM 0x02 298 | 299 | #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) 300 | #define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) 301 | #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) 302 | 303 | /* Copy, swap, convert BD Address */ 304 | static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) 305 | { 306 | return memcmp(ba1, ba2, sizeof(bdaddr_t)); 307 | } 308 | static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) 309 | { 310 | memcpy(dst, src, sizeof(bdaddr_t)); 311 | } 312 | 313 | void baswap(bdaddr_t *dst, const bdaddr_t *src); 314 | bdaddr_t *strtoba(const char *str); 315 | char *batostr(const bdaddr_t *ba); 316 | int ba2str(const bdaddr_t *ba, char *str); 317 | int str2ba(const char *str, bdaddr_t *ba); 318 | int ba2oui(const bdaddr_t *ba, char *oui); 319 | int bachk(const char *str); 320 | 321 | int baprintf(const char *format, ...); 322 | int bafprintf(FILE *stream, const char *format, ...); 323 | int basprintf(char *str, const char *format, ...); 324 | int basnprintf(char *str, size_t size, const char *format, ...); 325 | 326 | void *bt_malloc(size_t size); 327 | void bt_free(void *ptr); 328 | 329 | int bt_error(uint16_t code); 330 | const char *bt_compidtostr(int id); 331 | 332 | typedef struct { 333 | uint8_t data[16]; 334 | } uint128_t; 335 | 336 | #if __BYTE_ORDER == __BIG_ENDIAN 337 | 338 | #define ntoh64(x) (x) 339 | 340 | static inline void ntoh128(const uint128_t *src, uint128_t *dst) 341 | { 342 | memcpy(dst, src, sizeof(uint128_t)); 343 | } 344 | 345 | static inline void btoh128(const uint128_t *src, uint128_t *dst) 346 | { 347 | int i; 348 | 349 | for (i = 0; i < 16; i++) 350 | dst->data[15 - i] = src->data[i]; 351 | } 352 | 353 | #else 354 | 355 | static inline uint64_t ntoh64(uint64_t n) 356 | { 357 | uint64_t h; 358 | uint64_t tmp = ntohl(n & 0x00000000ffffffff); 359 | 360 | h = ntohl(n >> 32); 361 | h |= tmp << 32; 362 | 363 | return h; 364 | } 365 | 366 | static inline void ntoh128(const uint128_t *src, uint128_t *dst) 367 | { 368 | int i; 369 | 370 | for (i = 0; i < 16; i++) 371 | dst->data[15 - i] = src->data[i]; 372 | } 373 | 374 | static inline void btoh128(const uint128_t *src, uint128_t *dst) 375 | { 376 | memcpy(dst, src, sizeof(uint128_t)); 377 | } 378 | 379 | #endif 380 | 381 | #define hton64(x) ntoh64(x) 382 | #define hton128(x, y) ntoh128(x, y) 383 | #define htob128(x, y) btoh128(x, y) 384 | 385 | #ifdef __cplusplus 386 | } 387 | #endif 388 | 389 | #endif /* __BLUETOOTH_H */ 390 | -------------------------------------------------------------------------------- /cmdparse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo Link command text parser 3 | * 4 | * @date March 8, 2014 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "amcmd.h" 17 | #include "cmdparse.h" 18 | 19 | AMIIGO_CMD g_cmd = AMIIGO_CMD_NONE; 20 | amcfg_t g_cfg; 21 | extern char g_src[512]; 22 | 23 | // Initialize the command configs to defaults 24 | void cmd_init(void) { 25 | //---------- config packets ------------ 26 | memset(&g_cfg, 0, sizeof(g_cfg)); 27 | 28 | // Some defulats 29 | g_cfg.maint_led.duration = 5; 30 | g_cfg.maint_led.led = 6; 31 | g_cfg.maint_led.speed = 1; 32 | } 33 | 34 | void trim(char *str) 35 | { 36 | int i; 37 | int begin = 0; 38 | int end = strlen(str) - 1; 39 | 40 | while (isspace(str[begin])) 41 | begin++; 42 | 43 | while ((end >= begin) && isspace(str[end])) 44 | end--; 45 | 46 | // Shift all characters back to the start of the string array. 47 | for (i = begin; i <= end; i++) 48 | str[i - begin] = str[i]; 49 | 50 | str[i - begin] = '\0'; // Null terminate string. 51 | } 52 | 53 | int parse_command(const char * szName) { 54 | if (strcasecmp(szName, "download") == 0) { 55 | g_cmd = AMIIGO_CMD_DOWNLOAD; 56 | } else if (strcasecmp(szName, "resetcpu") == 0) { 57 | g_cmd = AMIIGO_CMD_RESET_CPU; 58 | } else if (strcasecmp(szName, "resetlogs") == 0) { 59 | g_cmd = AMIIGO_CMD_RESET_LOGS; 60 | } else if (strcasecmp(szName, "resetconfigs") == 0) { 61 | g_cmd = AMIIGO_CMD_RESET_CONFIGS; 62 | } else if (strcasecmp(szName, "configls") == 0) { 63 | g_cmd = AMIIGO_CMD_CONFIGLS; 64 | } else if (strcasecmp(szName, "configaccel") == 0) { 65 | g_cmd = AMIIGO_CMD_CONFIGACCEL; 66 | } else if (strcasecmp(szName, "configtemp") == 0) { 67 | g_cmd = AMIIGO_CMD_CONFIGTEMP; 68 | } else if (strcasecmp(szName, "blink") == 0) { 69 | g_cmd = AMIIGO_CMD_BLINK; 70 | } else if (strcasecmp(szName, "deepsleep") == 0) { 71 | g_cmd = AMIIGO_CMD_DEEPSLEEP; 72 | } else if (strcasecmp(szName, "status") == 0) { 73 | g_cmd = AMIIGO_CMD_NONE; 74 | } else if (strcasecmp(szName, "rename") == 0) { 75 | g_cmd = AMIIGO_CMD_RENAME; 76 | } else if (strcasecmp(szName, "tag") == 0) { 77 | g_cmd = AMIIGO_CMD_TAG; 78 | } else if (strcasecmp(szName, "test_seq") == 0) { 79 | g_cmd = AMIIGO_CMD_TEST_SEQ; 80 | } else if (strcasecmp(szName, "extstatus") == 0) { 81 | g_cmd = AMIIGO_CMD_EXTSTATUS; 82 | } else { 83 | fprintf(stderr, "Invalid command (%s)!\n", szName); 84 | return -1; 85 | } 86 | return 0; 87 | } 88 | 89 | int parse_mode(const char * szName) { 90 | if (strcasecmp(szName, "fast") == 0) { 91 | g_cfg.general.flags = CFG_NEW_MODE; 92 | g_cfg.general.usemode = RATE_FAST; 93 | } else if (strcasecmp(szName, "slow") == 0) { 94 | g_cfg.general.flags = CFG_NEW_MODE; 95 | g_cfg.general.usemode = RATE_SLOW; 96 | } else if (strcasecmp(szName, "sleep") == 0) { 97 | g_cfg.general.flags = CFG_NEW_MODE; 98 | g_cfg.general.usemode = RATE_SLEEP; 99 | } else { 100 | fprintf(stderr, "Invalid mode (%s)!\n", szName); 101 | return -1; 102 | } 103 | return 0; 104 | } 105 | 106 | int parse_adapter(const char * szName) { 107 | strcpy(g_src, szName); 108 | return 0; 109 | } 110 | 111 | int parse_device(const char * szName) { 112 | 113 | char * str = strdup(szName); 114 | 115 | char * pch; 116 | pch = strtok (str, ","); 117 | int dev_count = 0; 118 | while (pch != NULL) { 119 | if (dev_count >= MAX_DEV_COUNT) { 120 | fprintf(stderr, "Maximum of %d devices can be connected to\n", MAX_DEV_COUNT); 121 | return -1; 122 | } 123 | g_cfg.dst[dev_count] = pch; 124 | dev_count++; 125 | pch = strtok (NULL, ","); 126 | } 127 | if (dev_count == 0) { 128 | fprintf(stderr, "Invalid device address"); 129 | return -1; 130 | } 131 | g_cfg.count_dst = dev_count; 132 | return 0; 133 | } 134 | 135 | int parse_i2c_write(const char * szArg) { 136 | 137 | char * str = strdup(szArg); 138 | char * pch; 139 | pch = strtok (str, ":"); 140 | int arg_count = 0; 141 | while (pch != NULL) { 142 | arg_count++; 143 | if (arg_count == 1) 144 | g_cfg.i2c.address = (uint8)atoi(pch); 145 | else if (arg_count == 2) { 146 | g_cfg.i2c.reg = (uint8)atoi(pch); 147 | } else if (arg_count == 3) { 148 | g_cfg.i2c.data = (uint8)atoi(pch); 149 | } else { 150 | break; 151 | } 152 | pch = strtok (NULL, ":"); 153 | } 154 | if (arg_count != 3) { 155 | fprintf(stderr, "Invalid i2c address:reg:value format"); 156 | return -1; 157 | } 158 | g_cfg.i2c.write = 1; 159 | g_cmd = AMIIGO_CMD_I2C_WRITE; 160 | return 0; 161 | } 162 | 163 | int parse_i2c_read(const char * szArg) { 164 | char * str = strdup(szArg); 165 | char * pch; 166 | pch = strtok (str, ":"); 167 | int arg_count = 0; 168 | while (pch != NULL) { 169 | arg_count++; 170 | if (arg_count == 1) { 171 | g_cfg.i2c.address = (uint8)atoi(pch); 172 | } else if (arg_count == 2) { 173 | g_cfg.i2c.reg = (uint8)atoi(pch); 174 | } else { 175 | break; 176 | } 177 | pch = strtok (NULL, ":"); 178 | } 179 | if (arg_count != 2) { 180 | printf("Invalid i2c address:reg format"); 181 | return -1; 182 | } 183 | g_cfg.i2c.write = 0; 184 | g_cmd = AMIIGO_CMD_I2C_READ; 185 | return 0; 186 | } 187 | 188 | // Parse a single parameter 189 | int parse_config_single(const char * szParam) { 190 | int err = 0; 191 | switch (g_cmd) { 192 | case AMIIGO_CMD_RENAME: 193 | if (strlen(szParam) > DEV_NAME_LEN) 194 | return -1; 195 | strcpy(&g_cfg.name.name[0], szParam); 196 | break; 197 | default: 198 | fprintf(stderr,"Configuration parameter %s not recognized!\n", szParam); 199 | err = -1; 200 | break; 201 | } 202 | return err; 203 | } 204 | 205 | // Parse param = value pairs 206 | int set_config_pairs(const char * szParam, const char * szVal) { 207 | if (szVal == NULL || szVal[0] == 0 || isspace(szVal[0])) 208 | return parse_config_single(szParam); 209 | 210 | long val = strtol(szVal, NULL, 0); 211 | //---------- Light ---------------------------- 212 | if (strcasecmp(szParam, "ls_fast_interval") == 0) { 213 | // Seconds between samples in fast mode 214 | g_cfg.config_ls.fast_interval = (uint16_t) val; 215 | } else if (strcasecmp(szParam, "ls_slow_interval") == 0) { 216 | // Seconds between samples in slow mode 217 | g_cfg.config_ls.slow_interval = (uint16_t) val; 218 | } else if (strcasecmp(szParam, "ls_sleep_interval") == 0) { 219 | // Seconds between samples in sleep mode 220 | g_cfg.config_ls.sleep_interval = (uint16_t) val; 221 | } else if (strcasecmp(szParam, "ls_duration") == 0) { 222 | g_cfg.config_ls.manual_duration = (uint8_t) val; 223 | } else if (strcasecmp(szParam, "ls_fast_duration") == 0) { 224 | g_cfg.config_ls.durations[RATE_FAST] = (uint8_t) val; 225 | } else if (strcasecmp(szParam, "ls_slow_duration") == 0) { 226 | g_cfg.config_ls.durations[RATE_SLOW] = (uint8_t) val; 227 | } else if (strcasecmp(szParam, "ls_sleep_duration") == 0) { 228 | g_cfg.config_ls.durations[RATE_SLEEP] = (uint8_t) val; 229 | } else if (strcasecmp(szParam, "ls_debug") == 0) { 230 | g_cfg.config_ls.debug = (uint8_t) val; 231 | } else if (strcasecmp(szParam, "ls_flags") == 0) { 232 | g_cfg.config_ls.flags = (uint8_t) val; 233 | } else if (strcasecmp(szParam, "ls_movement") == 0) { 234 | g_cfg.config_ls.movement = (uint8_t) val; 235 | } else if (strcasecmp(szParam, "ls_duration_mul") == 0) { 236 | g_cfg.config_ls.duration_mul = (uint8_t) val; 237 | } 238 | // --------------- Blink ---------------------- 239 | else if (strcasecmp(szParam, "blink_duration") == 0) { 240 | g_cfg.maint_led.duration = (uint8_t) val; 241 | } 242 | else if (strcasecmp(szParam, "blink_led") == 0) { 243 | g_cfg.maint_led.led = (uint8_t) val; 244 | } 245 | else if (strcasecmp(szParam, "blink_speed") == 0) { 246 | g_cfg.maint_led.speed = (uint8_t) val; 247 | } 248 | // ---------------- Accel --------------------- 249 | else if (strcasecmp(szParam, "accel_slow_rate") == 0) { 250 | g_cfg.config_accel.slow_rate = WEDConfigRateParam( 251 | (uint32_t) val); 252 | } else if (strcasecmp(szParam, "accel_fast_rate") == 0) { 253 | g_cfg.config_accel.fast_rate = WEDConfigRateParam( 254 | (uint32_t) val); 255 | } else if (strcasecmp(szParam, "accel_sleep_rate") == 0) { 256 | g_cfg.config_accel.sleep_rate = WEDConfigRateParam( 257 | (uint32_t) val); 258 | } 259 | // ---------------- Temperature --------------------- 260 | else if (strcasecmp(szParam, "temp_slow_rate") == 0) { 261 | g_cfg.config_temp.slow_rate = WEDConfigRateParam( 262 | (uint32_t) val); 263 | } else if (strcasecmp(szParam, "temp_fast_rate") == 0) { 264 | g_cfg.config_temp.fast_rate = WEDConfigRateParam( 265 | (uint32_t) val); 266 | } else if (strcasecmp(szParam, "temp_sleep_rate") == 0) { 267 | g_cfg.config_temp.sleep_rate = WEDConfigRateParam( 268 | (uint32_t) val); 269 | } 270 | // ---------------- rename --------------------- 271 | else if (strcasecmp(szParam, "name") == 0) { 272 | if (strlen(szVal) > DEV_NAME_LEN) { 273 | fprintf(stderr, "Name cannot be more than %d characters", DEV_NAME_LEN); 274 | return -1; 275 | } 276 | strcpy(&g_cfg.name.name[0], szVal); 277 | } 278 | // ---------------- mode --------------------- 279 | else if (strcasecmp(szParam, "mode") == 0) { 280 | if (parse_mode(szVal)) 281 | return -1; 282 | } 283 | // ----------- accel test mode --------------- 284 | else if (strcasecmp(szParam, "test_mode") == 0) { 285 | g_cfg.test_mode = (uint8_t) val; 286 | } 287 | // ---------------- tag --------------------- 288 | else if (strcasecmp(szParam, "tag") == 0) { 289 | uint32_t uval = (uint32_t)val; 290 | memcpy(&g_cfg.general.tag[0], &uval, 4); 291 | } else { 292 | fprintf(stderr,"Configuration parameter %s not recognized!\n", szParam); 293 | return -1; 294 | } 295 | return 0; 296 | } 297 | 298 | // Parse one line of param or param=value 299 | int parse_one_pair(char * szLine) { 300 | char * pch = strchr(szLine, '='); 301 | if (pch == NULL) 302 | return parse_config_single(szLine); 303 | *pch = 0; 304 | return set_config_pairs(szLine, pch + 1); 305 | } 306 | 307 | // Parse single command line 308 | int parse_input_line(const char * szName) { 309 | int err = 0; 310 | char * szArg = strdup(szName); 311 | 312 | char * pch; 313 | pch = strtok (szArg, ","); 314 | while (pch != NULL) { 315 | err = parse_one_pair(pch); 316 | if (err) 317 | break; 318 | pch = strtok (NULL, ","); 319 | } 320 | 321 | free(szArg); 322 | return err; 323 | } 324 | 325 | // If file exists 326 | int parse_file_exists(const char * szName) { 327 | FILE * fp = fopen(szName, "r"); 328 | 329 | if (fp == NULL) 330 | return 0; 331 | 332 | fclose(fp); 333 | 334 | return 0; 335 | } 336 | 337 | // If the name is likely a file 338 | int parse_is_file_name(const char * szName) { 339 | int is_path = (strpbrk(szName, "./") != NULL); 340 | if (is_path) 341 | return 1; 342 | 343 | if (strpbrk(szName, "=,")) 344 | return 0; 345 | 346 | return 0; 347 | } 348 | 349 | // If the name is likely a file 350 | int parse_is_input_file(const char * szName) { 351 | if (parse_file_exists(szName)) 352 | return 1; 353 | 354 | if (parse_is_file_name(szName)) 355 | return 1; 356 | 357 | return 0; 358 | } 359 | 360 | // Parse file 361 | int parse_input_file(const char * szName) { 362 | // If it is detected to be sequence of param=value[,...] parse the line 363 | if (!parse_is_input_file(szName)) 364 | return parse_input_line(szName); 365 | 366 | char szCmd[256]; 367 | char szParam[256]; 368 | char szVal[256]; 369 | FILE * fp = fopen(szName, "r"); 370 | if (fp == NULL) { 371 | fprintf(stderr, "Configuration file (%s) not accessible!\n", szName); 372 | return -1; 373 | } 374 | while (fgets(szCmd, 256, fp) != NULL) { 375 | trim(szCmd); 376 | if (szCmd[0] == '#') 377 | continue; // Ignore comments 378 | if (sscanf(szCmd, "%s %s", szParam, szVal) != 2) 379 | { 380 | if (strlen(szCmd) > 1) 381 | { 382 | fprintf(stderr, "Command %s in %s not recognized!\n", szCmd, szName); 383 | fclose(fp); 384 | return -1; 385 | } 386 | continue; 387 | } 388 | 389 | int err = set_config_pairs(szParam, szVal); 390 | if (err) { 391 | fclose(fp); 392 | return err; 393 | } 394 | } 395 | 396 | fclose(fp); 397 | 398 | return 0; 399 | } 400 | -------------------------------------------------------------------------------- /amdev/amdev.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Amiigo Device helper 3 | 4 | Copyright Amiigo Inc. 5 | """ 6 | from __future__ import print_function 7 | import sys 8 | import argparse 9 | import time 10 | import dbus 11 | from dbus.mainloop.glib import DBusGMainLoop 12 | import gobject 13 | import logging 14 | import re 15 | import os 16 | from subprocess import Popen, PIPE, STDOUT 17 | import signal 18 | from threading import Thread 19 | 20 | try: 21 | from Queue import Queue, Empty 22 | except ImportError: 23 | from queue import Queue, Empty # python 3.x 24 | 25 | import datetime 26 | 27 | ON_POSIX = 'posix' in sys.builtin_module_names 28 | 29 | 30 | def enqueue_output(out, queue): 31 | for line in iter(out.readline, b''): 32 | queue.put(line) 33 | out.close() 34 | 35 | if __name__ == "__main__": 36 | logging.basicConfig() 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | BUS_NAME = 'org.bluez' 41 | SERVICE_NAME = 'org.bluez' 42 | ADAPTER_INTERFACE = SERVICE_NAME + '.Adapter1' 43 | DEVICE_INTERFACE = SERVICE_NAME + '.Device1' 44 | 45 | __version__ = 1.6 46 | 47 | 48 | class AmiigoDevice(): 49 | def __init__(self, force_amlink=False, force=False, adapter=''): 50 | self.done = False 51 | self.force_amlink = force_amlink 52 | self.force = force 53 | self.amiigos = {} 54 | self.timeout_secs = 10 55 | self.max_timeout = 30 56 | self.adapter = adapter 57 | 58 | if self.force_amlink: 59 | self._manager = None 60 | else: 61 | DBusGMainLoop(set_as_default=True) 62 | self._loop = gobject.MainLoop() 63 | self._bus = dbus.SystemBus() 64 | 65 | man = self._bus.get_object(BUS_NAME, '/') 66 | 67 | try: 68 | self._manager = dbus.Interface(man, 'org.freedesktop.DBus.ObjectManager') 69 | self._manager.GetManagedObjects() 70 | except: 71 | self._manager = None 72 | 73 | self.cmds_base = ['amlink'] 74 | if self.adapter: 75 | self.cmds_base = self.cmds_base + ['-i', self.adapter] 76 | 77 | def _keep_status(self, dut, stdout): 78 | logs = 0 79 | battery = 0 80 | charging = False 81 | recording = False 82 | version = '' 83 | stdout = stdout.rstrip().lower() 84 | if '(Rec)' in stdout: 85 | recording = True 86 | if 'charging' in stdout: 87 | charging = True 88 | if 'version:' in stdout: 89 | m = re.findall('version:\s(?P[.|0-9]+)\s', stdout) 90 | if m: 91 | version = m[0] 92 | if 'logs:' in stdout: 93 | m = re.findall('logs:\s(?P[0-9]+)\s', stdout) 94 | if m: 95 | logs = m[0] 96 | if 'battery:' in stdout: 97 | m = re.findall('battery:\s(?P[0-9]+)\%\s', stdout) 98 | if m: 99 | battery = m[0] 100 | return charging, battery, recording, logs, version 101 | 102 | def test(self, dut): 103 | """test blink 104 | """ 105 | 106 | charging = False 107 | 108 | passed = False 109 | 110 | cmds = self.cmds_base + ['--b', dut] 111 | 112 | cmds = cmds + ['--c', 'blink'] 113 | logger.info(cmds) 114 | p = Popen(cmds, stdout=PIPE, stderr=PIPE, close_fds=ON_POSIX, preexec_fn=os.setsid) 115 | stdout, stderr = p.communicate() 116 | if stderr: 117 | logger.debug({'stdout': stdout, 'stderr': stderr}) 118 | elif not stdout: 119 | print('no output') 120 | else: 121 | passed = True 122 | stdout = stdout.rstrip().lower() 123 | if 'charging' in stdout: 124 | charging = True 125 | 126 | if not passed: 127 | print('\tblink test did not pass, try again or change device') 128 | 129 | sys.stdout.flush() 130 | return passed, charging 131 | 132 | def discover_amlink(self, console=False): 133 | """discover using amlink 134 | """ 135 | 136 | pattern = '(?P
([0-9A-F]{2}:){5}[0-9A-F]{2})\s+(?:(?P.{13}[W|S][0-9A-F]{6})|\(unknown\))(?:\s+(?P[0-9A-F]{32}))?$' 137 | 138 | p = Popen(['amlink', '--lescan'], stdout=PIPE, stderr=STDOUT, bufsize=1, close_fds=ON_POSIX, preexec_fn=os.setsid) 139 | 140 | def _process(): 141 | 142 | def _process_line(line): 143 | m = re.match(pattern, line) 144 | if m: 145 | m = m.groupdict() 146 | address = m.get('address', '').upper() 147 | name = m.get('name', '') 148 | uuid = m.get('uuid', '') 149 | # if name is Amiigo-ish or if we have amiigo service uuid 150 | if name or uuid == 'CCA3100078C647859E450887D451317C': 151 | self.add_amiigo(address, name, console=console) 152 | q = Queue() 153 | t = Thread(target=enqueue_output, args=(p.stdout, q)) 154 | t.daemon = True # thread dies with the program 155 | t.start() 156 | 157 | _time = time.time() 158 | 159 | elapsed = 0 160 | done = False 161 | while not done: 162 | try: 163 | line = q.get(timeout=.1) 164 | except Empty: 165 | line = '' 166 | if line: 167 | line = line.rstrip() 168 | _process_line(line) 169 | elapsed = time.time() - _time 170 | done = elapsed > self.timeout_secs or self.done 171 | 172 | try: 173 | _process() 174 | except: 175 | pass 176 | 177 | try: 178 | os.kill(p.pid, signal.SIGINT) 179 | except: 180 | pass 181 | 182 | try: 183 | p.wait() 184 | except (KeyboardInterrupt, SystemExit): 185 | try: 186 | os.kill(p.pid, signal.SIGKILL) 187 | except: 188 | pass 189 | except: 190 | pass 191 | 192 | 193 | def is_amiigo(self, name): 194 | """check name ot see if it is amiigo 195 | """ 196 | is_amiigo = re.match('.{13}[W|S][0-9A-F]{6}$', name) is not None 197 | # print('test', name, is_amiigo) 198 | return is_amiigo 199 | 200 | def add_amiigo(self, address, name, rssi=0, console=False): 201 | """do something with amiigo 202 | """ 203 | if name is None: 204 | name = '' 205 | amiigo_type = self.amiigos.get(address, {}).get('type', '') 206 | if len(name) > 7: 207 | if name[-7] == 'S': 208 | amiigo_type = 'Shoepod' 209 | elif name[-7] == 'W': 210 | amiigo_type = 'Wristband' 211 | 212 | if not name: 213 | name = self.amiigos.get(address, {}).get('name', '(unknown)') 214 | 215 | rssi = int(rssi) 216 | amiigo = self.amiigos.get(address) 217 | new_amiigo = (amiigo is None or 218 | amiigo.get('type') != amiigo_type or 219 | amiigo.get('rssi') != rssi or 220 | amiigo.get('name') != name) 221 | 222 | self.amiigos[address] = {'dut': '', 223 | 'passed': False, 224 | 'bad z': False, 225 | 'type': amiigo_type, 226 | 'rssi': rssi, 227 | 'name': name} 228 | if console and new_amiigo: 229 | msg = 'Address: %s, RSSI: %s, Name: %s' % (address, rssi, name) 230 | if amiigo_type: 231 | msg = msg + ' %s' % amiigo_type 232 | print(msg) 233 | 234 | sys.stdout.flush() 235 | 236 | def _wait_start_discovery(self, adapter, timeout_secs): 237 | bus = self._bus 238 | device_prop = dbus.Interface(bus.get_object(BUS_NAME, adapter.object_path), 239 | 'org.freedesktop.DBus.Properties') 240 | 241 | _time = time.time() 242 | while time.time() - _time < timeout_secs: 243 | prop = device_prop.Get(ADAPTER_INTERFACE, 'Discovering') 244 | if prop == 1: 245 | break 246 | time.sleep(1) 247 | 248 | def _switch_on_adapter(self, adapter, on): 249 | bus = self._bus 250 | device_prop = dbus.Interface(bus.get_object(BUS_NAME, adapter.object_path), 251 | 'org.freedesktop.DBus.Properties') 252 | device_prop.Set(ADAPTER_INTERFACE, 'Powered', on) 253 | 254 | def discover(self, console=False): 255 | if self._manager is None or self.force_amlink: 256 | return self.discover_amlink(console=console) 257 | disc = self.discover_dbus(console=console) 258 | time.sleep(3) 259 | return disc 260 | 261 | def discover_dbus(self, console=False): 262 | bus = self._bus 263 | objects = self._manager.GetManagedObjects() 264 | adapters = [] 265 | for path, interfaces in objects.iteritems(): 266 | adapter = interfaces.get(ADAPTER_INTERFACE) 267 | if adapter is None: 268 | continue 269 | obj = bus.get_object(BUS_NAME, path) 270 | adapters.append(dbus.Interface(obj, ADAPTER_INTERFACE)) 271 | 272 | if len(adapters) == 0: 273 | raise RuntimeError('No BLE adapter found') 274 | 275 | adapter = adapters[0] 276 | if self.adapter: 277 | try: 278 | adapters = [a for a in adapters if self.adapter in a.object_path] 279 | if len(adapters): 280 | adapter = adapters[0] 281 | except: 282 | pass 283 | 284 | devices = dict() 285 | if self.force: 286 | # turn off adapter first 287 | self._switch_on_adapter(adapter, False) 288 | self._switch_on_adapter(adapter, True) 289 | 290 | def _scan_timeout(): 291 | adapter.StopDiscovery() 292 | self._loop.quit() 293 | return False 294 | 295 | def _interface_added(path, interfaces): 296 | path = unicode(path) 297 | if DEVICE_INTERFACE not in interfaces: 298 | return 299 | properties = dict(interfaces[DEVICE_INTERFACE]) 300 | if path in devices: 301 | logger.info('replace old device properties with new device properties') 302 | devices[path] = properties 303 | address = (unicode(properties['Address']) if 'Address' in properties else '') 304 | logger.info('Bluetooth Device Found: %s.', address) 305 | is_amiigo = False 306 | name = '' 307 | for key, value in properties.iteritems(): 308 | logger.info('\t%s : %s', key, value) 309 | if 'UUID' in key and value == 'cca31000-78c6-4785-9e45-0887d451317c': 310 | is_amiigo = True 311 | if key == 'Name' or (key == 'Alias' and not name): 312 | name = unicode(value) 313 | is_amiigo = is_amiigo or self.is_amiigo(name) 314 | properties['is_amiigo'] = is_amiigo 315 | rssi = int(properties.get('RSSI', 0)) 316 | msg = 'Address: %s, RSSI: %s, Name: %s' % (address, rssi, name) 317 | 318 | logger.info(msg) 319 | 320 | if is_amiigo: 321 | self.add_amiigo(address, name, rssi, console=console) 322 | 323 | sys.stdout.flush() 324 | 325 | def _device_property_changed(interface, changed, invalidated, path): 326 | path = unicode(path) 327 | logger.info('Device properties changed %s: %s at path %s', interface, changed, path) 328 | if interface != DEVICE_INTERFACE: 329 | logger.critical('should not get called with interface %s', interface) 330 | return 331 | address = (unicode(devices[path]['Address']) 332 | if path in devices and 'Address' in devices[path] 333 | else '') 334 | if address == '': 335 | address = changed.get('Address', address) 336 | 337 | properties = devices.get(path, {}) 338 | name = unicode(properties.get('Name', '')) 339 | rssi = int(properties.get('RSSI', 0)) 340 | msg = '^ Address: %s, RSSI: %s, Name: %s' % (address, rssi, name) 341 | logger.info(msg) 342 | 343 | is_amiigo = False 344 | if path in devices: 345 | is_amiigo = devices[path]['is_amiigo'] 346 | is_amiigo = is_amiigo or self.is_amiigo(name) 347 | if is_amiigo and address != '': 348 | self.add_amiigo(address, name, rssi, console=console) 349 | 350 | sys.stdout.flush() 351 | 352 | bus.add_signal_receiver(_interface_added, 353 | dbus_interface='org.freedesktop.DBus.ObjectManager', 354 | signal_name='InterfacesAdded') 355 | bus.add_signal_receiver(_device_property_changed, 356 | dbus_interface='org.freedesktop.DBus.Properties', 357 | signal_name='PropertiesChanged', 358 | arg0=DEVICE_INTERFACE, 359 | path_keyword='path') 360 | adapter.StartDiscovery() 361 | 362 | # wait a little 363 | self._wait_start_discovery(adapter, 3) 364 | 365 | # Scan for timeout_secs 366 | gobject.timeout_add(self.timeout_secs * 1000, _scan_timeout) 367 | try: 368 | self._loop.run() 369 | except (KeyboardInterrupt, SystemExit): 370 | pass 371 | except Exception as e: 372 | logger.critical('loop exception %s' % e) 373 | bus.remove_signal_receiver(_interface_added, 374 | dbus_interface='org.freedesktop.DBus.ObjectManager', 375 | signal_name='InterfacesAdded') 376 | bus.remove_signal_receiver(_device_property_changed, 377 | dbus_interface='org.freedesktop.DBus.Properties', 378 | signal_name='PropertiesChanged', 379 | arg0=DEVICE_INTERFACE, 380 | path_keyword='path') 381 | 382 | if self.force: 383 | # turn off adapter again 384 | self._switch_on_adapter(adapter, False) 385 | 386 | if console: 387 | print('... done listing ...') 388 | 389 | del self._manager 390 | del self._bus 391 | del self._loop 392 | 393 | 394 | 395 | def main(): 396 | description = "Amiigo Device manufacturing test (version {version})".format(version=__version__) 397 | parser = argparse.ArgumentParser(description=description) 398 | parser.add_argument("-l", "--list", dest="discover", help="List all devices.", 399 | action="store_true") 400 | parser.add_argument("--version", dest="version", help="Get the version of this test tool.", 401 | action="store_true") 402 | parser.add_argument("-v", "--verbose", dest="verbosity", default=0, nargs='?', const=2, 403 | help="logger verbosity") 404 | parser.add_argument("-a", "--amlink", dest="amlink", help="Force using amlink.", 405 | action="store_true") 406 | parser.add_argument("-f", "--force", dest="force", help="Force reset the adapter.", 407 | action="store_true") 408 | parser.add_argument("-i", "--interface", dest="interface", help="Interface adapter (default is hci0).") 409 | parser.add_argument("-t", "--test", dest="dut", nargs='1', help="Test a wristband given MAC address") 410 | 411 | if len(sys.argv) == 1: 412 | parser.print_help() 413 | 414 | options = parser.parse_args() 415 | 416 | if options.version: 417 | print("version {version}".format(version=__version__)) 418 | 419 | logger.setLevel("CRITICAL") 420 | if options.verbosity > 0: 421 | logger.setLevel("DEBUG") 422 | dev = AmiigoDevice(force_amlink=options.amlink, 423 | force=options.force, 424 | adapter=options.interface) 425 | 426 | if options.discover: 427 | dev.discover(console=True) 428 | 429 | if options.dut: 430 | dev.test(options.dut) 431 | 432 | return dev 433 | 434 | if __name__ == "__main__": 435 | engine = main() 436 | -------------------------------------------------------------------------------- /att.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2010 Nokia Corporation 6 | * Copyright (C) 2010 Marcel Holtmann 7 | * 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | /* 26 | * This code was originally part of the BlueZ protocol stack (hence the comments above) 27 | * but has been heavily modified to remove dependencies on glib, and make it a true low-level 28 | * protocol stack. 29 | * 30 | * Bluetooth UUID also added here as it seems symbols do not get exported in newer BlueZ-lib version. 31 | * 32 | */ 33 | 34 | #ifndef ATT_H 35 | #define ATT_H 36 | 37 | /* GATT Profile Attribute types */ 38 | #define GATT_PRIM_SVC_UUID 0x2800 39 | #define GATT_SND_SVC_UUID 0x2801 40 | #define GATT_INCLUDE_UUID 0x2802 41 | #define GATT_CHARAC_UUID 0x2803 42 | 43 | /* GATT Characteristic Types */ 44 | #define GATT_CHARAC_DEVICE_NAME 0x2A00 45 | #define GATT_CHARAC_APPEARANCE 0x2A01 46 | #define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02 47 | #define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03 48 | #define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04 49 | #define GATT_CHARAC_SERVICE_CHANGED 0x2A05 50 | 51 | /* GATT Characteristic Descriptors */ 52 | #define GATT_CHARAC_EXT_PROPER_UUID 0x2900 53 | #define GATT_CHARAC_USER_DESC_UUID 0x2901 54 | #define GATT_CLIENT_CHARAC_CFG_UUID 0x2902 55 | #define GATT_SERVER_CHARAC_CFG_UUID 0x2903 56 | #define GATT_CHARAC_FMT_UUID 0x2904 57 | #define GATT_CHARAC_AGREG_FMT_UUID 0x2905 58 | #define GATT_CHARAC_VALID_RANGE_UUID 0x2906 59 | #define GATT_EXTERNAL_REPORT_REFERENCE 0x2907 60 | #define GATT_REPORT_REFERENCE 0x2908 61 | 62 | /* Client Characteristic Configuration bit field */ 63 | #define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001 64 | #define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002 65 | 66 | // ------------------------------------ UUID ----------------------------- 67 | #define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb" 68 | 69 | #define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb" 70 | #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb" 71 | 72 | #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" 73 | #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" 74 | 75 | #define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb" 76 | 77 | #define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb" 78 | #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb" 79 | 80 | #define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb" 81 | #define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb" 82 | 83 | #define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb" 84 | #define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb" 85 | #define GN_UUID "00001117-0000-1000-8000-00805f9b34fb" 86 | #define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb" 87 | 88 | #define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb" 89 | #define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb" 90 | 91 | #define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb" 92 | #define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb" 93 | #define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb" 94 | #define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb" 95 | 96 | #define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb" 97 | 98 | #define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb" 99 | #define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb" 100 | #define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb" 101 | #define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb" 102 | 103 | #define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb" 104 | #define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb" 105 | #define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb" 106 | #define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb" 107 | #define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb" 108 | 109 | #define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb" 110 | #define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb" 111 | #define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb" 112 | #define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb" 113 | #define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb" 114 | 115 | #define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb" 116 | 117 | #define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb" 118 | #define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb" 119 | #define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb" 120 | 121 | #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" 122 | 123 | #define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" 124 | 125 | #define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb" 126 | #define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb" 127 | 128 | #define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb" 129 | 130 | #define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb" 131 | #define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb" 132 | #define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb" 133 | #define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb" 134 | #define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb" 135 | #define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb" 136 | #define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb" 137 | #define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb" 138 | #define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb" 139 | 140 | typedef struct { 141 | enum { 142 | BT_UUID_UNSPEC = 0, BT_UUID16 = 16, BT_UUID32 = 32, BT_UUID128 = 128, 143 | } type; 144 | union { 145 | uint16_t u16; 146 | uint32_t u32; 147 | uint128_t u128; 148 | } value; 149 | } bt_uuid_t; 150 | 151 | int bt_uuid_strcmp(const void *a, const void *b); 152 | 153 | int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value); 154 | int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value); 155 | int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value); 156 | 157 | int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2); 158 | void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst); 159 | 160 | #define MAX_LEN_UUID_STR 37 161 | 162 | int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n); 163 | int bt_string_to_uuid(bt_uuid_t *uuid, const char *string); 164 | 165 | // ------------------------------------ ATT ------------------------------------ 166 | 167 | /* Attribute Protocol Opcodes */ 168 | #define ATT_OP_ERROR 0x01 169 | #define ATT_OP_MTU_REQ 0x02 170 | #define ATT_OP_MTU_RESP 0x03 171 | #define ATT_OP_FIND_INFO_REQ 0x04 172 | #define ATT_OP_FIND_INFO_RESP 0x05 173 | #define ATT_OP_FIND_BY_TYPE_REQ 0x06 174 | #define ATT_OP_FIND_BY_TYPE_RESP 0x07 175 | #define ATT_OP_READ_BY_TYPE_REQ 0x08 176 | #define ATT_OP_READ_BY_TYPE_RESP 0x09 177 | #define ATT_OP_READ_REQ 0x0A 178 | #define ATT_OP_READ_RESP 0x0B 179 | #define ATT_OP_READ_BLOB_REQ 0x0C 180 | #define ATT_OP_READ_BLOB_RESP 0x0D 181 | #define ATT_OP_READ_MULTI_REQ 0x0E 182 | #define ATT_OP_READ_MULTI_RESP 0x0F 183 | #define ATT_OP_READ_BY_GROUP_REQ 0x10 184 | #define ATT_OP_READ_BY_GROUP_RESP 0x11 185 | #define ATT_OP_WRITE_REQ 0x12 186 | #define ATT_OP_WRITE_RESP 0x13 187 | #define ATT_OP_WRITE_CMD 0x52 188 | #define ATT_OP_PREP_WRITE_REQ 0x16 189 | #define ATT_OP_PREP_WRITE_RESP 0x17 190 | #define ATT_OP_EXEC_WRITE_REQ 0x18 191 | #define ATT_OP_EXEC_WRITE_RESP 0x19 192 | #define ATT_OP_HANDLE_NOTIFY 0x1B 193 | #define ATT_OP_HANDLE_IND 0x1D 194 | #define ATT_OP_HANDLE_CNF 0x1E 195 | #define ATT_OP_SIGNED_WRITE_CMD 0xD2 196 | 197 | /* Error codes for Error response PDU */ 198 | #define ATT_ECODE_INVALID_HANDLE 0x01 199 | #define ATT_ECODE_READ_NOT_PERM 0x02 200 | #define ATT_ECODE_WRITE_NOT_PERM 0x03 201 | #define ATT_ECODE_INVALID_PDU 0x04 202 | #define ATT_ECODE_AUTHENTICATION 0x05 203 | #define ATT_ECODE_REQ_NOT_SUPP 0x06 204 | #define ATT_ECODE_INVALID_OFFSET 0x07 205 | #define ATT_ECODE_AUTHORIZATION 0x08 206 | #define ATT_ECODE_PREP_QUEUE_FULL 0x09 207 | #define ATT_ECODE_ATTR_NOT_FOUND 0x0A 208 | #define ATT_ECODE_ATTR_NOT_LONG 0x0B 209 | #define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C 210 | #define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D 211 | #define ATT_ECODE_UNLIKELY 0x0E 212 | #define ATT_ECODE_INSUFF_ENC 0x0F 213 | #define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 214 | #define ATT_ECODE_INSUFF_RESOURCES 0x11 215 | /* Application error */ 216 | #define ATT_ECODE_IO 0x80 217 | #define ATT_ECODE_TIMEOUT 0x81 218 | #define ATT_ECODE_ABORTED 0x82 219 | 220 | /* Characteristic Property bit field */ 221 | #define ATT_CHAR_PROPER_BROADCAST 0x01 222 | #define ATT_CHAR_PROPER_READ 0x02 223 | #define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP 0x04 224 | #define ATT_CHAR_PROPER_WRITE 0x08 225 | #define ATT_CHAR_PROPER_NOTIFY 0x10 226 | #define ATT_CHAR_PROPER_INDICATE 0x20 227 | #define ATT_CHAR_PROPER_AUTH 0x40 228 | #define ATT_CHAR_PROPER_EXT_PROPER 0x80 229 | 230 | #define ATT_MAX_VALUE_LEN 512 231 | #define ATT_DEFAULT_L2CAP_MTU 48 232 | #define ATT_DEFAULT_LE_MTU 23 233 | 234 | #define ATT_CID 4 235 | #define ATT_PSM 31 236 | 237 | /* Flags for Execute Write Request Operation */ 238 | #define ATT_CANCEL_ALL_PREP_WRITES 0x00 239 | #define ATT_WRITE_ALL_PREP_WRITES 0x01 240 | 241 | /* Find Information Response Formats */ 242 | #define ATT_FIND_INFO_RESP_FMT_16BIT 0x01 243 | #define ATT_FIND_INFO_RESP_FMT_128BIT 0x02 244 | 245 | uint8_t is_response(uint8_t opcode); 246 | 247 | uint8_t opcode2expected(uint8_t opcode); 248 | 249 | struct att_data_list { 250 | uint16_t num; 251 | uint16_t len; 252 | uint8_t **data; 253 | }; 254 | 255 | struct att_range { 256 | uint16_t start; 257 | uint16_t end; 258 | }; 259 | 260 | struct gatt_primary { 261 | bt_uuid_t uuid; 262 | struct att_range range; 263 | }; 264 | 265 | struct gatt_included { 266 | bt_uuid_t uuid; 267 | uint16_t handle; 268 | struct att_range range; 269 | }; 270 | 271 | struct gatt_char { 272 | bt_uuid_t uuid; 273 | uint16_t handle; 274 | uint8_t properties; 275 | uint16_t value_handle; 276 | }; 277 | 278 | #define MAX_LEN_UUID_STR 37 279 | 280 | int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n); 281 | int bt_string_to_uuid(bt_uuid_t *uuid, const char *string); 282 | 283 | /* These functions do byte conversion */ 284 | static inline uint8_t att_get_u8(const void *ptr) { 285 | const uint8_t *u8_ptr = (const uint8_t *) ptr; 286 | return bt_get_unaligned(u8_ptr); 287 | } 288 | 289 | static inline uint16_t att_get_u16(const void *ptr) { 290 | const uint16_t *u16_ptr = (const uint16_t *) ptr; 291 | return btohs(bt_get_unaligned(u16_ptr)); 292 | } 293 | 294 | static inline uint32_t att_get_u32(const void *ptr) { 295 | const uint32_t *u32_ptr = (const uint32_t *) ptr; 296 | return btohl(bt_get_unaligned(u32_ptr)); 297 | } 298 | 299 | static inline uint128_t att_get_u128(const void *ptr) { 300 | const uint128_t *u128_ptr = (const uint128_t *) ptr; 301 | uint128_t dst; 302 | 303 | btoh128(u128_ptr, &dst); 304 | 305 | return dst; 306 | } 307 | 308 | static inline void att_put_u8(uint8_t src, void *dst) { 309 | bt_put_unaligned(src, (uint8_t *) dst); 310 | } 311 | 312 | static inline void att_put_u16(uint16_t src, void *dst) { 313 | bt_put_unaligned(htobs(src), (uint16_t *) dst); 314 | } 315 | 316 | static inline void att_put_u32(uint32_t src, void *dst) { 317 | bt_put_unaligned(htobl(src), (uint32_t *) dst); 318 | } 319 | 320 | static inline void att_put_u128(uint128_t src, void *dst) { 321 | uint128_t *d128 = (uint128_t *) dst; 322 | 323 | htob128(&src, d128); 324 | } 325 | 326 | static inline void att_put_uuid16(bt_uuid_t src, void *dst) { 327 | att_put_u16(src.value.u16, dst); 328 | } 329 | 330 | static inline void att_put_uuid128(bt_uuid_t src, void *dst) { 331 | att_put_u128(src.value.u128, dst); 332 | } 333 | 334 | static inline void att_put_uuid(bt_uuid_t src, void *dst) { 335 | if (src.type == BT_UUID16) 336 | att_put_uuid16(src, dst); 337 | else 338 | att_put_uuid128(src, dst); 339 | } 340 | 341 | static inline bt_uuid_t att_get_uuid16(const void *ptr) { 342 | bt_uuid_t uuid; 343 | 344 | bt_uuid16_create(&uuid, att_get_u16(ptr)); 345 | 346 | return uuid; 347 | } 348 | 349 | static inline bt_uuid_t att_get_uuid128(const void *ptr) { 350 | bt_uuid_t uuid; 351 | uint128_t value; 352 | 353 | value = att_get_u128(ptr); 354 | bt_uuid128_create(&uuid, value); 355 | 356 | return uuid; 357 | } 358 | 359 | struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len); 360 | void att_data_list_free(struct att_data_list *list); 361 | 362 | const char *att_ecode2str(uint8_t status); 363 | const char *att_op2str(uint8_t op); 364 | 365 | uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, 366 | uint8_t *pdu, size_t len); 367 | uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start, 368 | uint16_t *end, bt_uuid_t *uuid); 369 | uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, 370 | size_t len); 371 | uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, 372 | const uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); 373 | uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, 374 | uint16_t *end, bt_uuid_t *uuid, uint8_t *value, size_t *vlen); 375 | struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len); 376 | uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, 377 | uint8_t *pdu, size_t len); 378 | uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start, 379 | uint16_t *end, bt_uuid_t *uuid); 380 | uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, 381 | size_t len); 382 | uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen, 383 | uint8_t *pdu, size_t len); 384 | uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle, 385 | uint8_t *value, size_t *vlen); 386 | struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len); 387 | uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen, 388 | uint8_t *pdu, size_t len); 389 | uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, 390 | uint8_t *value, size_t *vlen); 391 | uint16_t enc_write_resp(uint8_t *pdu); 392 | uint16_t dec_write_resp(const uint8_t *pdu, size_t len); 393 | uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len); 394 | uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, 395 | size_t len); 396 | uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle); 397 | uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle, 398 | uint16_t *offset); 399 | uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); 400 | uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset, 401 | uint8_t *pdu, size_t len); 402 | ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value, 403 | size_t vlen); 404 | uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, 405 | uint8_t *pdu, size_t len); 406 | uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, 407 | size_t len); 408 | uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start, 409 | uint16_t *end); 410 | uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, 411 | uint8_t *pdu, size_t len); 412 | struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len, 413 | uint8_t *format); 414 | uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen, 415 | uint8_t *pdu, size_t len); 416 | uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen, 417 | uint8_t *pdu, size_t len); 418 | uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle, 419 | uint8_t *value, size_t vlen); 420 | uint16_t enc_confirmation(uint8_t *pdu, size_t len); 421 | 422 | uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len); 423 | uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu); 424 | uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len); 425 | uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu); 426 | 427 | uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset, 428 | const uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); 429 | uint16_t dec_prep_write_req(const uint8_t *pdu, size_t len, uint16_t *handle, 430 | uint16_t *offset, uint8_t *value, size_t *vlen); 431 | uint16_t enc_prep_write_resp(uint16_t handle, uint16_t offset, 432 | const uint8_t *value, size_t vlen, uint8_t *pdu, size_t len); 433 | uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle, 434 | uint16_t *offset, uint8_t *value, size_t *vlen); 435 | uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len); 436 | uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags); 437 | uint16_t enc_exec_write_resp(uint8_t *pdu); 438 | uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len); 439 | 440 | #endif 441 | -------------------------------------------------------------------------------- /jni/bluetooth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BlueZ - Bluetooth protocol stack for Linux 4 | * 5 | * Copyright (C) 2000-2001 Qualcomm Incorporated 6 | * Copyright (C) 2002-2003 Maxim Krasnyansky 7 | * Copyright (C) 2002-2010 Marcel Holtmann 8 | * 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "bluetooth.h" 39 | #include "hci.h" 40 | 41 | void baswap(bdaddr_t *dst, const bdaddr_t *src) 42 | { 43 | register unsigned char *d = (unsigned char *) dst; 44 | register const unsigned char *s = (const unsigned char *) src; 45 | register int i; 46 | 47 | for (i = 0; i < 6; i++) 48 | d[i] = s[5-i]; 49 | } 50 | 51 | char *batostr(const bdaddr_t *ba) 52 | { 53 | char *str = bt_malloc(18); 54 | if (!str) 55 | return NULL; 56 | 57 | sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", 58 | ba->b[0], ba->b[1], ba->b[2], 59 | ba->b[3], ba->b[4], ba->b[5]); 60 | 61 | return str; 62 | } 63 | 64 | bdaddr_t *strtoba(const char *str) 65 | { 66 | bdaddr_t b; 67 | bdaddr_t *ba = bt_malloc(sizeof(*ba)); 68 | 69 | if (ba) { 70 | str2ba(str, &b); 71 | baswap(ba, &b); 72 | } 73 | 74 | return ba; 75 | } 76 | 77 | int ba2str(const bdaddr_t *ba, char *str) 78 | { 79 | return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", 80 | ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]); 81 | } 82 | 83 | int str2ba(const char *str, bdaddr_t *ba) 84 | { 85 | int i; 86 | 87 | if (bachk(str) < 0) { 88 | memset(ba, 0, sizeof(*ba)); 89 | return -1; 90 | } 91 | 92 | for (i = 5; i >= 0; i--, str += 3) 93 | ba->b[i] = strtol(str, NULL, 16); 94 | 95 | return 0; 96 | } 97 | 98 | int ba2oui(const bdaddr_t *ba, char *str) 99 | { 100 | return sprintf(str, "%2.2X-%2.2X-%2.2X", ba->b[5], ba->b[4], ba->b[3]); 101 | } 102 | 103 | int bachk(const char *str) 104 | { 105 | if (!str) 106 | return -1; 107 | 108 | if (strlen(str) != 17) 109 | return -1; 110 | 111 | while (*str) { 112 | if (!isxdigit(*str++)) 113 | return -1; 114 | 115 | if (!isxdigit(*str++)) 116 | return -1; 117 | 118 | if (*str == 0) 119 | break; 120 | 121 | if (*str++ != ':') 122 | return -1; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | int baprintf(const char *format, ...) 129 | { 130 | va_list ap; 131 | int len; 132 | 133 | va_start(ap, format); 134 | len = vprintf(format, ap); 135 | va_end(ap); 136 | 137 | return len; 138 | } 139 | 140 | int bafprintf(FILE *stream, const char *format, ...) 141 | { 142 | va_list ap; 143 | int len; 144 | 145 | va_start(ap, format); 146 | len = vfprintf(stream, format, ap); 147 | va_end(ap); 148 | 149 | return len; 150 | } 151 | 152 | int basprintf(char *str, const char *format, ...) 153 | { 154 | va_list ap; 155 | int len; 156 | 157 | va_start(ap, format); 158 | len = vsnprintf(str, (~0U) >> 1, format, ap); 159 | va_end(ap); 160 | 161 | return len; 162 | } 163 | 164 | int basnprintf(char *str, size_t size, const char *format, ...) 165 | { 166 | va_list ap; 167 | int len; 168 | 169 | va_start(ap, format); 170 | len = vsnprintf(str, size, format, ap); 171 | va_end(ap); 172 | 173 | return len; 174 | } 175 | 176 | void *bt_malloc(size_t size) 177 | { 178 | return malloc(size); 179 | } 180 | 181 | void bt_free(void *ptr) 182 | { 183 | free(ptr); 184 | } 185 | 186 | /* Bluetooth error codes to Unix errno mapping */ 187 | int bt_error(uint16_t code) 188 | { 189 | switch (code) { 190 | case 0: 191 | return 0; 192 | case HCI_UNKNOWN_COMMAND: 193 | return EBADRQC; 194 | case HCI_NO_CONNECTION: 195 | return ENOTCONN; 196 | case HCI_HARDWARE_FAILURE: 197 | return EIO; 198 | case HCI_PAGE_TIMEOUT: 199 | return EHOSTDOWN; 200 | case HCI_AUTHENTICATION_FAILURE: 201 | return EACCES; 202 | case HCI_PIN_OR_KEY_MISSING: 203 | return EINVAL; 204 | case HCI_MEMORY_FULL: 205 | return ENOMEM; 206 | case HCI_CONNECTION_TIMEOUT: 207 | return ETIMEDOUT; 208 | case HCI_MAX_NUMBER_OF_CONNECTIONS: 209 | case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS: 210 | return EMLINK; 211 | case HCI_ACL_CONNECTION_EXISTS: 212 | return EALREADY; 213 | case HCI_COMMAND_DISALLOWED: 214 | case HCI_TRANSACTION_COLLISION: 215 | case HCI_ROLE_SWITCH_PENDING: 216 | return EBUSY; 217 | case HCI_REJECTED_LIMITED_RESOURCES: 218 | case HCI_REJECTED_PERSONAL: 219 | case HCI_QOS_REJECTED: 220 | return ECONNREFUSED; 221 | case HCI_HOST_TIMEOUT: 222 | return ETIMEDOUT; 223 | case HCI_UNSUPPORTED_FEATURE: 224 | case HCI_QOS_NOT_SUPPORTED: 225 | case HCI_PAIRING_NOT_SUPPORTED: 226 | case HCI_CLASSIFICATION_NOT_SUPPORTED: 227 | case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: 228 | case HCI_PARAMETER_OUT_OF_RANGE: 229 | case HCI_QOS_UNACCEPTABLE_PARAMETER: 230 | return EOPNOTSUPP; 231 | case HCI_INVALID_PARAMETERS: 232 | case HCI_SLOT_VIOLATION: 233 | return EINVAL; 234 | case HCI_OE_USER_ENDED_CONNECTION: 235 | case HCI_OE_LOW_RESOURCES: 236 | case HCI_OE_POWER_OFF: 237 | return ECONNRESET; 238 | case HCI_CONNECTION_TERMINATED: 239 | return ECONNABORTED; 240 | case HCI_REPEATED_ATTEMPTS: 241 | return ELOOP; 242 | case HCI_REJECTED_SECURITY: 243 | case HCI_PAIRING_NOT_ALLOWED: 244 | case HCI_INSUFFICIENT_SECURITY: 245 | return EACCES; 246 | case HCI_UNSUPPORTED_REMOTE_FEATURE: 247 | return EPROTONOSUPPORT; 248 | case HCI_SCO_OFFSET_REJECTED: 249 | return ECONNREFUSED; 250 | case HCI_UNKNOWN_LMP_PDU: 251 | case HCI_INVALID_LMP_PARAMETERS: 252 | case HCI_LMP_ERROR_TRANSACTION_COLLISION: 253 | case HCI_LMP_PDU_NOT_ALLOWED: 254 | case HCI_ENCRYPTION_MODE_NOT_ACCEPTED: 255 | return EPROTO; 256 | default: 257 | return ENOSYS; 258 | } 259 | } 260 | 261 | const char *bt_compidtostr(int compid) 262 | { 263 | switch (compid) { 264 | case 0: 265 | return "Ericsson Technology Licensing"; 266 | case 1: 267 | return "Nokia Mobile Phones"; 268 | case 2: 269 | return "Intel Corp."; 270 | case 3: 271 | return "IBM Corp."; 272 | case 4: 273 | return "Toshiba Corp."; 274 | case 5: 275 | return "3Com"; 276 | case 6: 277 | return "Microsoft"; 278 | case 7: 279 | return "Lucent"; 280 | case 8: 281 | return "Motorola"; 282 | case 9: 283 | return "Infineon Technologies AG"; 284 | case 10: 285 | return "Cambridge Silicon Radio"; 286 | case 11: 287 | return "Silicon Wave"; 288 | case 12: 289 | return "Digianswer A/S"; 290 | case 13: 291 | return "Texas Instruments Inc."; 292 | case 14: 293 | return "Ceva, Inc. (formerly Parthus Technologies, Inc.)"; 294 | case 15: 295 | return "Broadcom Corporation"; 296 | case 16: 297 | return "Mitel Semiconductor"; 298 | case 17: 299 | return "Widcomm, Inc"; 300 | case 18: 301 | return "Zeevo, Inc."; 302 | case 19: 303 | return "Atmel Corporation"; 304 | case 20: 305 | return "Mitsubishi Electric Corporation"; 306 | case 21: 307 | return "RTX Telecom A/S"; 308 | case 22: 309 | return "KC Technology Inc."; 310 | case 23: 311 | return "NewLogic"; 312 | case 24: 313 | return "Transilica, Inc."; 314 | case 25: 315 | return "Rohde & Schwarz GmbH & Co. KG"; 316 | case 26: 317 | return "TTPCom Limited"; 318 | case 27: 319 | return "Signia Technologies, Inc."; 320 | case 28: 321 | return "Conexant Systems Inc."; 322 | case 29: 323 | return "Qualcomm"; 324 | case 30: 325 | return "Inventel"; 326 | case 31: 327 | return "AVM Berlin"; 328 | case 32: 329 | return "BandSpeed, Inc."; 330 | case 33: 331 | return "Mansella Ltd"; 332 | case 34: 333 | return "NEC Corporation"; 334 | case 35: 335 | return "WavePlus Technology Co., Ltd."; 336 | case 36: 337 | return "Alcatel"; 338 | case 37: 339 | return "Philips Semiconductors"; 340 | case 38: 341 | return "C Technologies"; 342 | case 39: 343 | return "Open Interface"; 344 | case 40: 345 | return "R F Micro Devices"; 346 | case 41: 347 | return "Hitachi Ltd"; 348 | case 42: 349 | return "Symbol Technologies, Inc."; 350 | case 43: 351 | return "Tenovis"; 352 | case 44: 353 | return "Macronix International Co. Ltd."; 354 | case 45: 355 | return "GCT Semiconductor"; 356 | case 46: 357 | return "Norwood Systems"; 358 | case 47: 359 | return "MewTel Technology Inc."; 360 | case 48: 361 | return "ST Microelectronics"; 362 | case 49: 363 | return "Synopsis"; 364 | case 50: 365 | return "Red-M (Communications) Ltd"; 366 | case 51: 367 | return "Commil Ltd"; 368 | case 52: 369 | return "Computer Access Technology Corporation (CATC)"; 370 | case 53: 371 | return "Eclipse (HQ Espana) S.L."; 372 | case 54: 373 | return "Renesas Technology Corp."; 374 | case 55: 375 | return "Mobilian Corporation"; 376 | case 56: 377 | return "Terax"; 378 | case 57: 379 | return "Integrated System Solution Corp."; 380 | case 58: 381 | return "Matsushita Electric Industrial Co., Ltd."; 382 | case 59: 383 | return "Gennum Corporation"; 384 | case 60: 385 | return "Research In Motion"; 386 | case 61: 387 | return "IPextreme, Inc."; 388 | case 62: 389 | return "Systems and Chips, Inc."; 390 | case 63: 391 | return "Bluetooth SIG, Inc."; 392 | case 64: 393 | return "Seiko Epson Corporation"; 394 | case 65: 395 | return "Integrated Silicon Solution Taiwan, Inc."; 396 | case 66: 397 | return "CONWISE Technology Corporation Ltd"; 398 | case 67: 399 | return "PARROT SA"; 400 | case 68: 401 | return "Socket Mobile"; 402 | case 69: 403 | return "Atheros Communications, Inc."; 404 | case 70: 405 | return "MediaTek, Inc."; 406 | case 71: 407 | return "Bluegiga"; 408 | case 72: 409 | return "Marvell Technology Group Ltd."; 410 | case 73: 411 | return "3DSP Corporation"; 412 | case 74: 413 | return "Accel Semiconductor Ltd."; 414 | case 75: 415 | return "Continental Automotive Systems"; 416 | case 76: 417 | return "Apple, Inc."; 418 | case 77: 419 | return "Staccato Communications, Inc."; 420 | case 78: 421 | return "Avago Technologies"; 422 | case 79: 423 | return "APT Licensing Ltd."; 424 | case 80: 425 | return "SiRF Technology"; 426 | case 81: 427 | return "Tzero Technologies, Inc."; 428 | case 82: 429 | return "J&M Corporation"; 430 | case 83: 431 | return "Free2move AB"; 432 | case 84: 433 | return "3DiJoy Corporation"; 434 | case 85: 435 | return "Plantronics, Inc."; 436 | case 86: 437 | return "Sony Ericsson Mobile Communications"; 438 | case 87: 439 | return "Harman International Industries, Inc."; 440 | case 88: 441 | return "Vizio, Inc."; 442 | case 89: 443 | return "Nordic Semiconductor ASA"; 444 | case 90: 445 | return "EM Microelectronic-Marin SA"; 446 | case 91: 447 | return "Ralink Technology Corporation"; 448 | case 92: 449 | return "Belkin International, Inc."; 450 | case 93: 451 | return "Realtek Semiconductor Corporation"; 452 | case 94: 453 | return "Stonestreet One, LLC"; 454 | case 95: 455 | return "Wicentric, Inc."; 456 | case 96: 457 | return "RivieraWaves S.A.S"; 458 | case 97: 459 | return "RDA Microelectronics"; 460 | case 98: 461 | return "Gibson Guitars"; 462 | case 99: 463 | return "MiCommand Inc."; 464 | case 100: 465 | return "Band XI International, LLC"; 466 | case 101: 467 | return "Hewlett-Packard Company"; 468 | case 102: 469 | return "9Solutions Oy"; 470 | case 103: 471 | return "GN Netcom A/S"; 472 | case 104: 473 | return "General Motors"; 474 | case 105: 475 | return "A&D Engineering, Inc."; 476 | case 106: 477 | return "MindTree Ltd."; 478 | case 107: 479 | return "Polar Electro OY"; 480 | case 108: 481 | return "Beautiful Enterprise Co., Ltd."; 482 | case 109: 483 | return "BriarTek, Inc."; 484 | case 110: 485 | return "Summit Data Communications, Inc."; 486 | case 111: 487 | return "Sound ID"; 488 | case 112: 489 | return "Monster, LLC"; 490 | case 113: 491 | return "connectBlue AB"; 492 | case 114: 493 | return "ShangHai Super Smart Electronics Co. Ltd."; 494 | case 115: 495 | return "Group Sense Ltd."; 496 | case 116: 497 | return "Zomm, LLC"; 498 | case 117: 499 | return "Samsung Electronics Co. Ltd."; 500 | case 118: 501 | return "Creative Technology Ltd."; 502 | case 119: 503 | return "Laird Technologies"; 504 | case 120: 505 | return "Nike, Inc."; 506 | case 121: 507 | return "lesswire AG"; 508 | case 122: 509 | return "MStar Semiconductor, Inc."; 510 | case 123: 511 | return "Hanlynn Technologies"; 512 | case 124: 513 | return "A & R Cambridge"; 514 | case 125: 515 | return "Seers Technology Co. Ltd"; 516 | case 126: 517 | return "Sports Tracking Technologies Ltd."; 518 | case 127: 519 | return "Autonet Mobile"; 520 | case 128: 521 | return "DeLorme Publishing Company, Inc."; 522 | case 129: 523 | return "WuXi Vimicro"; 524 | case 130: 525 | return "Sennheiser Communications A/S"; 526 | case 131: 527 | return "TimeKeeping Systems, Inc."; 528 | case 132: 529 | return "Ludus Helsinki Ltd."; 530 | case 133: 531 | return "BlueRadios, Inc."; 532 | case 134: 533 | return "equinox AG"; 534 | case 135: 535 | return "Garmin International, Inc."; 536 | case 136: 537 | return "Ecotest"; 538 | case 137: 539 | return "GN ReSound A/S"; 540 | case 138: 541 | return "Jawbone"; 542 | case 139: 543 | return "Topcorn Positioning Systems, LLC"; 544 | case 140: 545 | return "Qualcomm Labs, Inc."; 546 | case 141: 547 | return "Zscan Software"; 548 | case 142: 549 | return "Quintic Corp."; 550 | case 143: 551 | return "Stollman E+V GmbH"; 552 | case 144: 553 | return "Funai Electric Co., Ltd."; 554 | case 145: 555 | return "Advanced PANMOBIL Systems GmbH & Co. KG"; 556 | case 146: 557 | return "ThinkOptics, Inc."; 558 | case 147: 559 | return "Universal Electronics, Inc."; 560 | case 148: 561 | return "Airoha Technology Corp."; 562 | case 149: 563 | return "NEC Lighting, Ltd."; 564 | case 150: 565 | return "ODM Technology, Inc."; 566 | case 151: 567 | return "Bluetrek Technologies Limited"; 568 | case 152: 569 | return "zer01.tv GmbH"; 570 | case 153: 571 | return "i.Tech Dynamic Global Distribution Ltd."; 572 | case 154: 573 | return "Alpwise"; 574 | case 155: 575 | return "Jiangsu Toppower Automotive Electronics Co., Ltd."; 576 | case 156: 577 | return "Colorfy, Inc."; 578 | case 157: 579 | return "Geoforce Inc."; 580 | case 158: 581 | return "Bose Corporation"; 582 | case 159: 583 | return "Suunto Oy"; 584 | case 160: 585 | return "Kensington Computer Products Group"; 586 | case 161: 587 | return "SR-Medizinelektronik"; 588 | case 162: 589 | return "Vertu Corporation Limited"; 590 | case 163: 591 | return "Meta Watch Ltd."; 592 | case 164: 593 | return "LINAK A/S"; 594 | case 165: 595 | return "OTL Dynamics LLC"; 596 | case 166: 597 | return "Panda Ocean Inc."; 598 | case 167: 599 | return "Visteon Corporation"; 600 | case 168: 601 | return "ARP Devices Limited"; 602 | case 169: 603 | return "Magneti Marelli S.p.A"; 604 | case 170: 605 | return "CAEN RFID srl"; 606 | case 171: 607 | return "Ingenieur-Systemgruppe Zahn GmbH"; 608 | case 172: 609 | return "Green Throttle Games"; 610 | case 173: 611 | return "Peter Systemtechnik GmbH"; 612 | case 174: 613 | return "Omegawave Oy"; 614 | case 175: 615 | return "Cinetix"; 616 | case 176: 617 | return "Passif Semiconductor Corp"; 618 | case 177: 619 | return "Saris Cycling Group, Inc"; 620 | case 178: 621 | return "Bekey A/S"; 622 | case 179: 623 | return "Clarinox Technologies Pty. Ltd."; 624 | case 180: 625 | return "BDE Technology Co., Ltd."; 626 | case 181: 627 | return "Swirl Networks"; 628 | case 182: 629 | return "Meso international"; 630 | case 183: 631 | return "TreLab Ltd"; 632 | case 184: 633 | return "Qualcomm Innovation Center, Inc. (QuIC)"; 634 | case 185: 635 | return "Johnson Controls, Inc."; 636 | case 186: 637 | return "Starkey Laboratories Inc."; 638 | case 187: 639 | return "S-Power Electronics Limited"; 640 | case 188: 641 | return "Ace Sensor Inc"; 642 | case 189: 643 | return "Aplix Corporation"; 644 | case 190: 645 | return "AAMP of America"; 646 | case 191: 647 | return "Stalmart Technology Limited"; 648 | case 192: 649 | return "AMICCOM Electronics Corporation"; 650 | case 193: 651 | return "Shenzhen Excelsecu Data Technology Co.,Ltd"; 652 | case 194: 653 | return "Geneq Inc."; 654 | case 195: 655 | return "adidas AG"; 656 | case 196: 657 | return "LG Electronics"; 658 | case 197: 659 | return "Onset Computer Corporation"; 660 | case 198: 661 | return "Selfly BV"; 662 | case 199: 663 | return "Quuppa Oy."; 664 | case 200: 665 | return "GeLo Inc"; 666 | case 201: 667 | return "Evluma"; 668 | case 202: 669 | return "MC10"; 670 | case 203: 671 | return "Binauric SE"; 672 | case 204: 673 | return "Beats Electronics"; 674 | case 205: 675 | return "Microchip Technology Inc."; 676 | case 206: 677 | return "Elgato Systems GmbH"; 678 | case 207: 679 | return "ARCHOS SA"; 680 | case 209: 681 | return "Polar Electro Europe B.V."; 682 | case 210: 683 | return "Dialog Semiconductor B.V."; 684 | case 211: 685 | return "Taixingbang Technology (HK) Co,. LTD."; 686 | case 212: 687 | return "Kawantech"; 688 | case 213: 689 | return "Austco Communication Systems"; 690 | case 214: 691 | return "Timex Group USA, Inc."; 692 | case 215: 693 | return "Qualcomm Technologies, Inc."; 694 | case 216: 695 | return "Qualcomm Connected Experiences, Inc."; 696 | case 217: 697 | return "Voyetra Turtle Beach"; 698 | case 218: 699 | return "txtr GmbH"; 700 | case 219: 701 | return "Biosentronics"; 702 | case 65535: 703 | return "internal use"; 704 | default: 705 | return "not assigned"; 706 | } 707 | } 708 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Amiigo offline utility 3 | * 4 | * @date Aug 25, 2013 5 | * @author: dashesy 6 | * @copyright Amiigo Inc. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "amidefs.h" 21 | #include "amdev.h" 22 | #include "hcitool.h" 23 | #include "common.h" 24 | #include "gapproto.h" 25 | #include "amproto.h" 26 | #include "amoldproto.h" 27 | #include "amlprocess.h" 28 | #include "cmdparse.h" 29 | #include "fwupdate.h" 30 | 31 | extern void char_init(void); 32 | extern char g_szBaseName[256]; 33 | 34 | int g_amver_major = 1; 35 | int g_amver_minor = 5; 36 | 37 | // TODO: have option of multiple sources 38 | char g_src[512] = "hci0"; // Device to connect from 39 | 40 | aml_options_t g_opt; // flags option 41 | 42 | // Execute the requested command 43 | int exec_command(amdev_t * dev) { 44 | dev->started = 1; 45 | switch (g_cmd) { 46 | case AMIIGO_CMD_NONE: 47 | dev->state = STATE_COUNT; // Done with command 48 | break; 49 | case AMIIGO_CMD_DOWNLOAD: 50 | if (dev->status.num_log_entries == 0 && !g_opt.live) { 51 | // Nothing to download! 52 | dev->state = STATE_COUNT; // Done with command 53 | return 0; 54 | } 55 | 56 | dev->state = STATE_DOWNLOAD; // Download in progress 57 | dev->total_logs = dev->status.num_log_entries; // How many logs to download 58 | return exec_download(dev->sock); 59 | break; 60 | case AMIIGO_CMD_CONFIGLS: 61 | dev->state = STATE_COUNT; // Done with command 62 | if (dev->ver_flat < FW_VERSION(1,8,117)) 63 | return exec_configls_18116(dev->sock); 64 | else 65 | return exec_configls(dev->sock); 66 | break; 67 | case AMIIGO_CMD_CONFIGACCEL: 68 | dev->state = STATE_COUNT; // Done with command 69 | return exec_configaccel(dev->sock); 70 | break; 71 | case AMIIGO_CMD_CONFIGTEMP: 72 | dev->state = STATE_COUNT; // Done with command 73 | return exec_configtemp(dev->sock); 74 | break; 75 | case AMIIGO_CMD_BLINK: 76 | dev->state = STATE_COUNT; // Done with command 77 | return exec_blink(dev->sock); 78 | break; 79 | case AMIIGO_CMD_DEEPSLEEP: 80 | dev->state = STATE_COUNT; // Done with command 81 | return exec_deepsleep(dev->sock); 82 | break; 83 | case AMIIGO_CMD_RESET_CPU: 84 | case AMIIGO_CMD_RESET_LOGS: 85 | case AMIIGO_CMD_RESET_CONFIGS: 86 | dev->state = STATE_COUNT; // Done with command 87 | return exec_reset(dev->sock, g_cmd); 88 | break; 89 | case AMIIGO_CMD_FWUPDATE: 90 | dev->state = STATE_FWSTATUS; 91 | return exec_fwupdate(dev->sock); 92 | break; 93 | case AMIIGO_CMD_I2C_READ: 94 | case AMIIGO_CMD_I2C_WRITE: 95 | dev->state = STATE_I2C; 96 | return exec_debug_i2c(dev->sock); 97 | break; 98 | case AMIIGO_CMD_RENAME: 99 | dev->state = STATE_COUNT; // Done with command 100 | return exec_rename(dev->sock); 101 | break; 102 | case AMIIGO_CMD_TAG: 103 | dev->state = STATE_COUNT; // Done with command 104 | return exec_tag(dev->sock); 105 | break; 106 | case AMIIGO_CMD_TEST_SEQ: 107 | dev->state = STATE_COUNT; // Done with command 108 | return exec_test_seq(dev->sock); 109 | break; 110 | case AMIIGO_CMD_EXTSTATUS: 111 | dev->state = STATE_EXTSTATUS; 112 | return exec_extstatus(dev->sock); 113 | break; 114 | default: 115 | return 0; 116 | break; 117 | } 118 | return 0; 119 | } 120 | 121 | void show_usage_screen(void) { 122 | printf("Amiigo Link command line utility version %d.%d\n", g_amver_major, g_amver_minor); 123 | printf("Usage: amlink [options] [command] [input|output]\n" 124 | "Options:\n" 125 | " -v, --verbose Verbose mode \n" 126 | " More messages are dumped to console.\n" 127 | " --full Full characteristics discovery. \n" 128 | " If specified handles are queried.\n" 129 | " --i, --adapter uuid|hci[,...]\n" 130 | " Interface adapter(s) to use (default is hci0)\n" 131 | " --b, --device uuid1[,...] \n" 132 | " Amiigo device(s) to connect to, default is shoepod then wristband.\n" 133 | " Example: --b 90:59:AF:04:32:82\n" 134 | " Use --lescan to find the UUID list\n" 135 | " --compressed Leave logs in compressed form.\n" 136 | " --append append to end of file.\n" 137 | " --raw Download logs in raw format (no compression).\n" 138 | " -l, --live Live download as a stream.\n" 139 | " Hit `q` to end the stream.\n" 140 | " --print\n" 141 | " Print accelerometer to console as well as the log file.\n" 142 | "Command:\n" 143 | " --lescan \n" 144 | " Low energy scan (needs root priviledge)\n" 145 | " --c, --command cmd \n" 146 | " Command to execute:\n" 147 | " status: (default) perform device discovery\n" 148 | " download: download the logs\n" 149 | " configls: configure light sensor\n" 150 | " configaccel: configure acceleration sensors\n" 151 | " configtemp: configure temperature sensor\n" 152 | " blink: configure blink LED\n" 153 | " deepsleep: go to deep sleep and only wake on hard double tap\n" 154 | " resetlogs: reset buffered logs\n" 155 | " resetcpu: restart the board\n" 156 | " resetconfigs: set all configs to default\n" 157 | " rename: rename the device\n" 158 | " tag: set a tag\n" 159 | " test_seq: set test sequence mode to test_mode\n" 160 | " extstatus: read extended status\n" 161 | " --mode fast|slow|sleep\n" 162 | " Switch to slow or fast mode after tag\n" 163 | " --input filename|param1=val1[,...]\n" 164 | " Configuration file to use for given command.\n" 165 | " Or input line sequence to specify parameters on command line.\n" 166 | " --fwupdate file\n" 167 | " Firmware image file to to use for update.\n" 168 | " --i2c_read address:reg\n" 169 | " Read i2c address and register (debugging only).\n" 170 | " --i2c_write address:reg:value\n" 171 | " Write value to i2c address and register (debugging only).\n" 172 | " --help Display this usage screen\n" 173 | "Parameters:\n" 174 | " parameters in a file are in the form of on each line\n" 175 | " parameters on a command line are in the form of = and are separated by comma.\n" 176 | " light sensor parameters: ls_fast_interval, ls_slow_interval, ls_sleep_interval, ls_duration, " 177 | "ls_fast_duration, ls_slow_duration, ls_sleep_duration, ls_debug, ls_flags, ls_movement, ls_duration_mul\n" 178 | " accelerometer parameters: accel_slow_rate, accel_fast_rate, accel_sleep_rate, test_mode, mode\n" 179 | " temperature parameters: temp_slow_rate, temp_fast_rate, temp_sleep_rate\n" 180 | "Input Output: (optional) \n" 181 | " If running download command, will be taken as output file\n" 182 | " Otherwise will be taken as input file name or line sequence\n" 183 | ); 184 | printf("\namlink is Copyright Amiigo inc\n"); 185 | } 186 | 187 | void show_version(void) { 188 | printf("Amiigo Link command line utility version %d.%d\n", g_amver_major, g_amver_minor); 189 | printf("\namlink is Copyright Amiigo inc\n"); 190 | } 191 | 192 | static void do_command_line(int argc, char * const argv[]) { 193 | // Parse the input 194 | while (1) { 195 | 196 | int c; 197 | int option_index = 0; 198 | static struct option long_options[] = { 199 | { "verbose", 0, 0, 'v' }, 200 | { "version", 0, 0, 'V' }, 201 | { "live", 0, 0, 'l' }, 202 | { "full", 0, 0, 'a' }, 203 | { "compressed", 0, 0, 'p'}, 204 | { "raw", 0, 0, 'r'}, 205 | { "append", 0, 0, 'A' }, 206 | { "lescan", 0, 0, 's' }, 207 | { "i", 1, 0, 'i' }, 208 | { "adapter", 1, 0, 'i' }, 209 | { "b", 1, 0, 'b' }, 210 | { "device", 1, 0, 'b' }, 211 | { "c", 1, 0, 'x' }, 212 | { "command", 1, 0, 'x' }, 213 | { "input", 1, 0, 'f' }, 214 | { "mode", 1, 0, 'm'}, 215 | { "print", 0, 0, 'o' }, 216 | { "i2c_read", 1, 0, 'd'}, 217 | { "i2c_write", 1, 0, 'w'}, 218 | { "fwupdate", 1, 0, 'u' }, 219 | { "help", 0, 0, '?' }, 220 | { 0, 0, 0, 0 } }; 221 | 222 | c = getopt_long(argc, argv, "vl?", long_options, &option_index); 223 | 224 | if (c == -1) 225 | break; 226 | 227 | switch (c) { 228 | case 0: 229 | printf("option %s", long_options[option_index].name); 230 | if (optarg) 231 | printf(" with arg %s", optarg); 232 | printf("unsupported\n"); 233 | break; 234 | 235 | case 'i': 236 | if (parse_adapter(optarg)) 237 | exit(1); 238 | break; 239 | 240 | case 's': 241 | do_lescan(); 242 | exit(0); 243 | break; 244 | 245 | case 'o': 246 | g_opt.console = 1; 247 | break; 248 | 249 | case 'l': 250 | g_opt.live = 1; 251 | break; 252 | 253 | case 'v': 254 | g_opt.verbosity = 1; 255 | break; 256 | 257 | case 'V': 258 | show_version(); 259 | exit(0); 260 | break; 261 | 262 | case 'a': 263 | g_opt.full = 1; 264 | break; 265 | 266 | case 'p': 267 | g_opt.leave_compressed = 1; 268 | break; 269 | 270 | case 'r': 271 | g_opt.raw = 1; 272 | break; 273 | 274 | case 'A': 275 | g_opt.append = 1; 276 | break; 277 | 278 | case 'b': 279 | if (parse_device(optarg)) 280 | exit(1); 281 | break; 282 | 283 | case 'x': 284 | if (parse_command(optarg)) 285 | exit(1); 286 | break; 287 | 288 | case 'm': 289 | if (parse_mode(optarg)) 290 | exit(1); 291 | break; 292 | 293 | case 'f': 294 | if (parse_input_file(optarg)) 295 | exit(1); 296 | break; 297 | 298 | case 'u': 299 | if (set_update_file(optarg)) 300 | exit(1); 301 | break; 302 | 303 | case 'd': 304 | if (parse_i2c_read(optarg)) 305 | exit(1); 306 | break; 307 | 308 | case 'w': 309 | if (parse_i2c_write(optarg)) 310 | exit(1); 311 | break; 312 | 313 | case '?': 314 | show_usage_screen(); 315 | exit(0); 316 | break; 317 | 318 | default: 319 | printf("?? getopt returned character code 0%o ??\n", c); 320 | break; 321 | } 322 | } 323 | 324 | if (argc == 1) { 325 | show_version(); 326 | exit(0); 327 | } 328 | 329 | int err = 0; 330 | if (optind == argc - 1) { 331 | // Parse the last reamining argument 332 | if (g_cmd == AMIIGO_CMD_DOWNLOAD) { 333 | strcpy(&g_szBaseName[0], argv[optind]); 334 | } else { 335 | err = parse_input_file(argv[optind]); 336 | } 337 | 338 | } else if (optind < argc) { 339 | printf("Unrecognized command line arguments: "); 340 | while (optind < argc) 341 | printf("%s ", argv[optind++]); 342 | printf("\n"); 343 | err = 1; 344 | } 345 | if (err) { 346 | printf("Use --help to get the list of valid commands and options\n"); 347 | exit(1); 348 | } 349 | } 350 | 351 | char kbhit() { 352 | struct termios oldt, newt; 353 | int ch; 354 | tcgetattr(STDIN_FILENO, &oldt); 355 | newt = oldt; 356 | newt.c_lflag &= ~( ICANON | ECHO); 357 | newt.c_cc[VMIN] = 0; 358 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); 359 | int nread = read(STDIN_FILENO, &ch, 1); 360 | tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 361 | if (nread == 1) 362 | return ch; 363 | else 364 | return 0; 365 | } 366 | 367 | int main(int argc, char **argv) { 368 | int ret, i; 369 | time_t start_time[MAX_DEV_COUNT], stop_time[MAX_DEV_COUNT], download_time[MAX_DEV_COUNT]; 370 | 371 | // do not buffer output 372 | setbuf(stdout, NULL); 373 | 374 | // Initialize the characteristics 375 | char_init(); 376 | // Initialize the command configs 377 | cmd_init(); 378 | 379 | // Amiigo devices to interact with 380 | amdev_t devices[MAX_DEV_COUNT]; 381 | // zero-fill the devices state 382 | memset(&devices[0], 0, sizeof(devices)); 383 | 384 | // Set parameters based on command line 385 | do_command_line(argc, argv); 386 | 387 | for (i = 0; i < g_cfg.count_dst; ++i) { 388 | amdev_t * dev = &devices[i]; 389 | dev->dev_idx = i; // Keep the index for reference 390 | // Connect to all devices 391 | dev->sock = gap_connect(g_src, g_cfg.dst[i]); 392 | if (dev->sock < 0) { 393 | return -1; 394 | } 395 | if (g_opt.full) { 396 | // Start by discovering Amiigo handles 397 | ret = discover_handles(dev->sock, OPT_START_HANDLE, OPT_END_HANDLE); 398 | if (ret) { 399 | fprintf(stderr, "discover_handles() error %d in %s\n", ret, g_cfg.dst[i]); 400 | return -1; 401 | } 402 | } else { 403 | // Use default handles and discover the device 404 | ret = discover_device(dev); 405 | if (ret) { 406 | fprintf(stderr, "discover_device() error %d in %s\n", ret, g_cfg.dst[i]); 407 | return -1; 408 | } 409 | } 410 | 411 | // Timing of downloads 412 | start_time[i]= time(NULL); 413 | stop_time[i] = start_time[i]; 414 | download_time[i] = start_time[i]; 415 | } 416 | 417 | int done_count = 0; // Number of devices done with their command 418 | int dev_idx = g_cfg.count_dst - 1; 419 | for (;;) { 420 | // See if user ended the run 421 | if (kbhit() == 'q') 422 | break; 423 | dev_idx--; 424 | if (dev_idx < 0) 425 | dev_idx = g_cfg.count_dst - 1; 426 | amdev_t * dev = &devices[dev_idx]; 427 | 428 | // No need to keep-alive during firmware update 429 | if (dev->state != STATE_FWSTATUS_WAIT) { 430 | stop_time[dev_idx] = time(NULL); 431 | double diff = difftime(stop_time[dev_idx], start_time[dev_idx]); 432 | // Keep-alive by reading status every 60s 433 | if (diff > 60) { 434 | if (g_opt.verbosity) 435 | printf(" (Keep alive %s)\n", g_cfg.dst[dev_idx]); 436 | start_time[dev_idx] = stop_time[dev_idx]; 437 | // Read the status to keep conection alive 438 | exec_status(dev->sock); 439 | } 440 | // If downloading (non-live) and not already done 441 | if (dev->state == STATE_DOWNLOAD && !g_opt.live && !dev->done) { 442 | diff = difftime(stop_time[dev_idx], download_time[dev_idx]); 443 | // Download timeout reached 444 | if (diff > 2) 445 | { 446 | printf(" (Timeout %s)\n", g_cfg.dst[dev_idx]); 447 | break; 448 | } 449 | } 450 | } 451 | 452 | uint8_t buf[1024] = {0}; 453 | int len = gap_recv(dev->sock, &buf[0], sizeof(buf)); 454 | if (len < 0) 455 | break; 456 | if (len == 0) 457 | continue; 458 | 459 | // Last time apacket came 460 | download_time[dev_idx] = stop_time[dev_idx]; 461 | 462 | // Process incoming data 463 | ret = process_data(dev, buf, len); 464 | if (ret) { 465 | fprintf(stderr, "main process_data() error %d in %s\n", ret, g_cfg.dst[dev_idx]); 466 | break; 467 | } 468 | 469 | // If all devices have their status read, execute the requested command 470 | if (dev->status.battery_level > 0 && dev->state != STATE_COUNT && !dev->started) { 471 | // Now that we have status (e.g. number of logs) of all devices 472 | // Start execution of the requested command 473 | ret = exec_command(dev); 474 | if (ret) { 475 | fprintf(stderr, "exec_command() error %d in %s\n", ret, g_cfg.dst[dev_idx]); 476 | break; 477 | } 478 | } 479 | 480 | if (dev->state == STATE_COUNT) { 481 | if (!dev->done) { 482 | dev->done = 1; 483 | done_count++; 484 | } 485 | // Done the the command on all devices 486 | if (done_count == g_cfg.count_dst) 487 | break; 488 | } 489 | 490 | } //end for(;; 491 | 492 | for (i = 0; i < g_cfg.count_dst; ++i) { 493 | amdev_t * dev = &devices[i]; 494 | // Reset CPU if need to exit in the middle of firmware update 495 | if (dev->state == STATE_FWSTATUS_WAIT) 496 | exec_reset(dev->sock, AMIIGO_CMD_RESET_CPU); 497 | 498 | 499 | // Close the socket 500 | gap_shutdown(dev->sock); 501 | 502 | // Close log files 503 | if (dev->logFile != NULL) 504 | { 505 | fclose(dev->logFile); 506 | dev->logFile = NULL; 507 | } 508 | } // } //end for( 509 | 510 | printf("\n"); 511 | return 0; 512 | } 513 | -------------------------------------------------------------------------------- /data_parser/input_parser.py: -------------------------------------------------------------------------------- 1 | """ Input data parser 2 | This should be just simple parsing of known Amiigo offline data files. 3 | This is not supposed to be called by engines directly, only by instrumented instances that work offline. 4 | 5 | The result is a data structure that exactly mimicks the input to engines when called by platform. 6 | This ensures the engine code will *only* need to care about the format as supplied by platform/server. 7 | 8 | Copyright Amiigo Inc. 9 | """ 10 | 11 | import sys 12 | import os 13 | import time 14 | import re 15 | import zipfile 16 | import StringIO 17 | import numpy as np 18 | import json 19 | import datetime 20 | from dateutil.parser import parse as date_parser 21 | from os.path import basename 22 | import csv 23 | 24 | 25 | class ParseError(ValueError): 26 | pass 27 | 28 | 29 | class ParseErrorFile(ParseError): 30 | pass 31 | 32 | 33 | class ParseErrorNotExist(ParseErrorFile): 34 | pass 35 | 36 | 37 | class ParseErrorUnknownType(ParseErrorFile): 38 | pass 39 | 40 | 41 | # ---------------------------------------------------------------------------------------------------------------------- 42 | class SensorData(object): 43 | """Sensor data 44 | """ 45 | def __init__(self, name, data, device='amiigo', **kwargs): 46 | """ 47 | Constructor 48 | Inputs: 49 | name - name of the sensor data type 50 | data - actual sensor data 51 | device - device type 52 | kwargs - additional arguments: 53 | """ 54 | self.name = name 55 | 56 | if name == 'accelerometer': 57 | if isinstance(data, basestring): 58 | data = json.loads(data) 59 | self.x = np.int16(data[0]) 60 | self.y = np.int16(data[1]) 61 | self.z = np.int16(data[2]) 62 | self.data_repr = (lambda self: '[%s,%s,%s]' % (self.x, self.y, self.z)) 63 | 64 | elif name == 'temperature': 65 | if isinstance(data, basestring): 66 | data = data.replace("'", '"') 67 | data = json.loads(data) 68 | try: 69 | self.celsius = data['celsius'] 70 | except: 71 | self.celsius = float(data) 72 | self.data_repr = (lambda self: '[%s]' % self.celsius) 73 | 74 | elif name == 'timestamp' or name == 'debug': 75 | self.name = 'timestamp' 76 | if isinstance(data, basestring): 77 | data = data.replace("'", '"') 78 | data = data.replace('True', '1') 79 | data = data.replace('False', '0') 80 | data = json.loads(data) 81 | if isinstance(data, float) or isinstance(data, int) or isinstance(data, np.double): 82 | data = {'seconds': data, 'errcode': data, 'ticks': np.uint32(data * 128)} 83 | elif isinstance(data, list): 84 | data = {'seconds': data[0] / 128.0, 'flags': np.uint8(data[1]), 'errcode': data[0], 'ticks': data[0]} 85 | 86 | self.flags = np.uint8(data.get('flags', 0)) 87 | self.seconds = data.get('seconds', 0) 88 | self.reboot = data.get('reboot', self.flags & 0x80) 89 | self.debug = data.get('debug', self.flags & 0x10) 90 | self.fast_rate = data.get('fast_rate', self.flags & 0x01) 91 | self.sleep = data.get('sleep', self.flags & 0x02) 92 | self.passive = data.get('passive', False) 93 | self.errcode = data.get('errcode', 0) 94 | self.data = data 95 | self.ticks = data.get('ticks', 0) 96 | 97 | self.data_repr = (lambda self: '[%s, %s]' % (self.ticks, self.flags)) 98 | elif name == 'lightsensor': 99 | if isinstance(data, basestring): 100 | data = data.replace("'", '"') 101 | data = json.loads(data) 102 | if isinstance(data, list): 103 | data = dict(data) 104 | self.ir = int(data.get('ir', 0)) 105 | self.red = int(data.get('red', 0)) 106 | self.off = int(data.get('off', 0)) 107 | self.data_repr = (lambda self: '[%s,%s,%s]' % (self.ir, self.off, self.red)) 108 | elif name == 'lightsensor_config': 109 | if isinstance(data, basestring): 110 | data = data.replace("'", '"') 111 | data = data.replace('(', '[') 112 | data = data.replace(')', ']') 113 | data = json.loads(data) 114 | if isinstance(data, list): 115 | data = dict(data) 116 | self.dac_on = int(data['dac_on']) 117 | self.gain = int(data['gain']) 118 | self.level_led = int(data['level_led']) 119 | self.log_size = int(data['log_size']) 120 | self.flags = int(data.get('flags', data.get('reserved', 0))) 121 | self.manual = data.get('manual', self.flags & 1) 122 | self.worn = data.get('worn', self.flags & 2) 123 | self.data_repr = (lambda self: '[%s, %s, %s, %s]' % (self.dac_on, self.gain, self.level_led, self.log_size)) 124 | elif name == 'log_count': 125 | if isinstance(data, basestring): 126 | data = data.replace("'", '"') 127 | data = data.replace("(", '[') 128 | data = data.replace(")", ']') 129 | data = json.loads(data) 130 | if isinstance(data, list): 131 | data = dict(data) 132 | self.log_timestamp = np.uint32(data['log_timestamp']) 133 | self.log_accel_count = np.uint16(data['log_accel_count']) 134 | self.old_timestamp = np.uint32(data['old_timestamp']) 135 | self.timestamp = np.uint32(data['timestamp']) 136 | self.data_repr = (lambda self: '[%s, %s, %s, %s]' % (self.log_timestamp, self.log_accel_count, self.old_timestamp, self.timestamp)) 137 | elif name == 'event': 138 | if isinstance(data, basestring): 139 | data = data.replace("'", '"') 140 | data = data.replace("(", '[') 141 | data = data.replace(")", ']') 142 | data = json.loads(data) 143 | if isinstance(data, list): 144 | data = dict(data) 145 | self.flags = np.uint8(data['flags']) 146 | self.data_repr = (lambda self: '[%s]' % self.flags) 147 | else: 148 | self.data = data 149 | self.data_repr = (lambda self: '[%s]' % self.data) 150 | 151 | def __repr__(self): 152 | return '%s,%s' % (self.name, self.data_repr(self)) 153 | 154 | 155 | class AmiigoParser(object): 156 | """ Generic parser for Amiigo data files 157 | """ 158 | 159 | def __init__(self, **kwargs): 160 | """ Constructor 161 | """ 162 | # Match for (LABEL)[_REF][_(COMMENT)].csv 163 | # label is alphanumeric, without underscore 164 | # comment can be anything 165 | self.match_string = r"^(?P