diff options
Diffstat (limited to 'arduino/libraries/Bluefruit52Lib/src/services')
18 files changed, 3532 insertions, 0 deletions
diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp new file mode 100755 index 0000000..2cfd172 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.cpp @@ -0,0 +1,66 @@ +/**************************************************************************/ +/*! + @file BLEBas.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +BLEBas::BLEBas(void) : + BLEService(UUID16_SVC_BATTERY), _battery(UUID16_CHR_BATTERY_LEVEL) +{ + +} + +err_t BLEBas::begin(void) +{ + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + _battery.setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); // could support notify + _battery.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); + _battery.setFixedLen(1); + VERIFY_STATUS( _battery.begin() ); + + return ERROR_NONE; +} + +bool BLEBas::write(uint8_t level) +{ + return _battery.write8(level) > 0; +} + +bool BLEBas::notify(uint8_t level) +{ + return _battery.notify8(level); +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h new file mode 100755 index 0000000..d091ce5 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBas.h @@ -0,0 +1,60 @@ +/**************************************************************************/ +/*! + @file BLEBas.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEBAS_H_ +#define BLEBAS_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +class BLEBas : public BLEService +{ + protected: + BLECharacteristic _battery; + + public: + BLEBas(void); + + virtual err_t begin(void); + + bool write (uint8_t level); + bool notify(uint8_t level); +}; + + + +#endif /* BLEBAS_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp new file mode 100755 index 0000000..21d3120 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.cpp @@ -0,0 +1,126 @@ +/**************************************************************************/ +/*! + @file BLEBeacon.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +void BLEBeacon::_init(void) +{ + _manufacturer_id = UUID16_COMPANY_ID_APPLE; // default is Apple + _uuid128 = NULL; + + _major_be = _minor_be = 0; + _rssi_at_1m = -54; +} + +BLEBeacon::BLEBeacon(void) +{ + _init(); +} + +BLEBeacon::BLEBeacon(uint8_t const uuid128[16]) +{ + _init(); + _uuid128 = uuid128; +} + +BLEBeacon::BLEBeacon(uint8_t const uuid128[16], uint16_t major, uint16_t minor, int8_t rssi) +{ + _init(); + _uuid128 = uuid128; + _major_be = __swap16(major); + _minor_be = __swap16(minor); + _rssi_at_1m = rssi; +} + +void BLEBeacon::setManufacturer(uint16_t manfacturer) +{ + _manufacturer_id = manfacturer; +} + +void BLEBeacon::setUuid(uint8_t const uuid128[16]) +{ + _uuid128 = uuid128; +} + +void BLEBeacon::setMajorMinor(uint16_t major, uint16_t minor) +{ + _major_be = major; + _minor_be = minor; +} + +void BLEBeacon::setRssiAt1m(int8_t rssi) +{ + _rssi_at_1m = rssi; +} + +bool BLEBeacon::start(void) +{ + return start(Bluefruit.Advertising); +} + +bool BLEBeacon::start(BLEAdvertising& adv) +{ + adv.clearData(); + + struct ATTR_PACKED + { + uint16_t manufacturer; + + uint8_t beacon_type; + uint8_t beacon_len; + + uint8_t uuid128[16]; + uint16_t major; + uint16_t minor; + int8_t rssi_at_1m; + } beacon_data = + { + .manufacturer = _manufacturer_id, + .beacon_type = 0x02, + .beacon_len = sizeof(beacon_data) - 4, // len of uuid + major + minor + rssi + .uuid128 = { 0 }, + .major = _major_be, + .minor = _minor_be, + .rssi_at_1m = _rssi_at_1m + }; + + VERIFY_STATIC(sizeof(beacon_data) == 25); + + memcpy(beacon_data.uuid128, _uuid128, 16); + + adv.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + return adv.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, &beacon_data, sizeof(beacon_data)); +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h new file mode 100755 index 0000000..d138813 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEBeacon.h @@ -0,0 +1,73 @@ +/**************************************************************************/ +/*! + @file BLEBeacon.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEBEACON_H_ +#define BLEBEACON_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +class BLEAdvertising; // forward declare + +class BLEBeacon +{ + private: + uint16_t _manufacturer_id; + uint8_t const* _uuid128; + uint16_t _major_be; // Big Endian + uint16_t _minor_be; // Big Endian + int8_t _rssi_at_1m; + + void _init(void); + + public: + BLEBeacon(void); + BLEBeacon(uint8_t const uuid128[16]); + BLEBeacon(uint8_t const uuid128[16], uint16_t major, uint16_t minor, int8_t rssi); + + void setManufacturer(uint16_t manfacturer); + void setUuid(uint8_t const uuid128[16]); + void setMajorMinor(uint16_t major, uint16_t minor); + void setRssiAt1m(int8_t rssi); + + bool start(void); + bool start(BLEAdvertising& adv); +}; + + + +#endif /* BLEBEACON_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp new file mode 100755 index 0000000..3ff2516 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.cpp @@ -0,0 +1,223 @@ +/**************************************************************************/ +/*! + @file BLEDfu.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +#define DFU_REV_APPMODE 0x0001 + +/* DFU Serivce : 00001530-1212-EFDE-1523-785FEABCD123 + * DFU Control : 00001531-1212-EFDE-1523-785FEABCD123 + * DFU Packet : 00001532-1212-EFDE-1523-785FEABCD123 + * DFU Revision: 00001534-1212-EFDE-1523-785FEABCD123 + */ + +const uint8_t UUID128_SVC_DFU_OTA[16] = +{ + 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, + 0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00 +}; + + +const uint8_t UUID128_CHR_DFU_CONTROL[16] = +{ + 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, + 0xDE, 0xEF, 0x12, 0x12, 0x31, 0x15, 0x00, 0x00 +}; + +const uint8_t UUID128_CHR_DFU_PACKET[16] = +{ + 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, + 0xDE, 0xEF, 0x12, 0x12, 0x32, 0x15, 0x00, 0x00 +}; + +const uint8_t UUID128_CHR_DFU_REVISON[16] = +{ + 0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, + 0xDE, 0xEF, 0x12, 0x12, 0x34, 0x15, 0x00, 0x00 +}; + +extern "C" void bootloader_util_app_start(uint32_t start_addr); + +static uint16_t crc16(const uint8_t* data_p, uint8_t length) +{ + uint8_t x; + uint16_t crc = 0xFFFF; + + while ( length-- ) + { + x = crc >> 8 ^ *data_p++; + x ^= x >> 4; + crc = (crc << 8) ^ ((uint16_t) (x << 12)) ^ ((uint16_t) (x << 5)) ^ ((uint16_t) x); + } + return crc; +} + +static void bledfu_control_wr_authorize_cb(BLECharacteristic& chr, ble_gatts_evt_write_t* request) +{ + if ( (request->handle == chr.handles().value_handle) && + (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) && + (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && + (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) + { + uint16_t conn_hdl = Bluefruit.connHandle(); + + ble_gatts_rw_authorize_reply_params_t reply = { .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE }; + + if ( !chr.notifyEnabled() ) + { + reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + return; + } + + reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + + enum { START_DFU = 1 }; + if ( request->data[0] == START_DFU ) + { + // Peer data information so that bootloader could re-connect after reboot + typedef struct { + ble_gap_addr_t addr; + ble_gap_irk_t irk; + ble_gap_enc_key_t enc_key; + uint8_t sys_attr[8]; + uint16_t crc16; + }peer_data_t; + + VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60); + + /* Save Peer data + * Peer data address is defined in bootloader linker @0x20007F80 + * - If bonded : save Security information + * - Otherwise : save Address for direct advertising + * + * TODO may force bonded only for security reason + */ + peer_data_t* peer_data = (peer_data_t*) (0x20007F80UL); + varclr(peer_data); + + // Get CCCD + uint16_t sysattr_len = sizeof(peer_data->sys_attr); + sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); + + // Get Bond Data or using Address if not bonded + peer_data->addr = Bluefruit.Gap.getPeerAddr(conn_hdl); + + if ( Bluefruit.Gap.paired(conn_hdl) ) + { + bond_keys_t bkeys; + + if ( bond_load_keys( BLE_GAP_ROLE_PERIPH, Bluefruit.Gap._get_peer(conn_hdl)->ediv, &bkeys ) ) + { + peer_data->addr = bkeys.peer_id.id_addr_info; + peer_data->irk = bkeys.peer_id.id_info; + peer_data->enc_key = bkeys.own_enc; + } + } + + // Calculate crc + peer_data->crc16 = crc16((uint8_t*) peer_data, offsetof(peer_data_t, crc16)); + + // Initiate DFU Sequence and reboot into DFU OTA mode + Bluefruit.Advertising.restartOnDisconnect(false); + Bluefruit.disconnect(); + + // Set GPReset to DFU OTA + enum { DFU_OTA_MAGIC = 0xB1 }; + + sd_power_gpregret_clr(0, 0xFF); + VERIFY_STATUS( sd_power_gpregret_set(0, DFU_OTA_MAGIC), ); + VERIFY_STATUS( sd_softdevice_disable(), ); + + // Disable all interrupts + #if defined(NRF52832_XXAA) + #define MAX_NUMBER_INTERRUPTS 39 + #elif defined(NRF52840_XXAA) + #define MAX_NUMBER_INTERRUPTS 48 + #endif + + NVIC_ClearPendingIRQ(SD_EVT_IRQn); + for(int i=0; i < MAX_NUMBER_INTERRUPTS; i++) + { + NVIC_DisableIRQ( (IRQn_Type) i ); + } + + // Clear RTC1 timer to prevent Interrupt happens after changing vector table +// NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk; +// NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk; +// NRF_RTC1->TASKS_STOP = 1; +// NRF_RTC1->TASKS_CLEAR = 1; + + VERIFY_STATUS( sd_softdevice_vector_table_base_set(NRF_UICR->NRFFW[0]), ); + + __set_CONTROL(0); // switch to MSP, required if using FreeRTOS + bootloader_util_app_start(NRF_UICR->NRFFW[0]); + } + } +} + +BLEDfu::BLEDfu(void) : BLEService(UUID128_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) +{ + +} + +err_t BLEDfu::begin(void) +{ + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + // No need to keep packet & revision characteristics + BLECharacteristic chr_packet(UUID128_CHR_DFU_PACKET); + chr_packet.setTempMemory(); + chr_packet.setProperties(CHR_PROPS_WRITE_WO_RESP); + chr_packet.setMaxLen(20); + VERIFY_STATUS( chr_packet.begin() ); + + _chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_NOTIFY); + _chr_control.setMaxLen(23); + _chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb); + VERIFY_STATUS( _chr_control.begin() ); + + BLECharacteristic chr_revision(UUID128_CHR_DFU_REVISON); + chr_revision.setTempMemory(); + chr_revision.setProperties(CHR_PROPS_READ); + chr_revision.setFixedLen(2); + VERIFY_STATUS( chr_revision.begin()); + chr_revision.write16(DFU_REV_APPMODE); + + return ERROR_NONE; +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h new file mode 100755 index 0000000..224a338 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDfu.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/*! + @file BLEDfu.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEDFU_H_ +#define BLEDFU_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +class BLEDfu : public BLEService +{ + protected: + BLECharacteristic _chr_control; + + public: + BLEDfu(void); + + virtual err_t begin(void); +}; + +#endif /* BLEDFU_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp new file mode 100755 index 0000000..c1a08e6 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.cpp @@ -0,0 +1,101 @@ +/**************************************************************************/ +/*! + @file BLEDis.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" +#include "utility/utilities.h" + +BLEDis::BLEDis(void) + : BLEService(UUID16_SVC_DEVICE_INFORMATION) +{ +#ifdef NRF52840_XXAA + _model = "Bluefruit Feather nRF52840"; +#else + _model = "Bluefruit Feather nRF52832"; +#endif + + _serial = NULL; + _firmware_rev = NULL; + _hardware_rev = NULL; + _software_rev = ARDUINO_BSP_VERSION; + _manufacturer = "Adafruit Industries"; +} + +void BLEDis::setModel(const char* model) +{ + _model = model; +} + +void BLEDis::setHardwareRev(const char* hw_rev) +{ + _hardware_rev = hw_rev; +} + +void BLEDis::setSoftwareRev(const char* sw_rev) +{ + _software_rev = sw_rev; +} + +void BLEDis::setManufacturer(const char* manufacturer) +{ + _manufacturer = manufacturer; +} + +err_t BLEDis::begin(void) +{ + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + _serial = getMcuUniqueID(); + _firmware_rev = getBootloaderVersion(); + + for(uint8_t i=0; i<arrcount(_strarr); i++) + { + if ( _strarr[i] != NULL ) + { + BLECharacteristic chars(UUID16_CHR_MODEL_NUMBER_STRING+i); + chars.setTempMemory(); + + chars.setProperties(CHR_PROPS_READ); + chars.setFixedLen(strlen(_strarr[i])); + + VERIFY_STATUS( chars.begin() ); + chars.write(_strarr[i]); + } + } + + return ERROR_NONE; +} + diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h new file mode 100755 index 0000000..bc5e710 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEDis.h @@ -0,0 +1,72 @@ +/**************************************************************************/ +/*! + @file BLEDis.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEDIS_H_ +#define BLEDIS_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +class BLEDis : public BLEService +{ + protected: + union { + struct { + const char * _model; + const char * _serial; + const char * _firmware_rev; + const char * _hardware_rev; + const char * _software_rev; + const char * _manufacturer; + }; + + const char * _strarr[6]; + }; + + public: + BLEDis(void); + + void setModel(const char* model); + void setHardwareRev(const char* hw_rev); + void setSoftwareRev(const char* sw_rev); + void setManufacturer(const char* manufacturer); + + virtual err_t begin(void); +}; + + +#endif /* BLEDIS_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp new file mode 100755 index 0000000..3657f3a --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.cpp @@ -0,0 +1,394 @@ +/**************************************************************************/ +/*! + @file BLEHidAdafruit.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +enum +{ + REPORT_ID_KEYBOARD = 1, + REPORT_ID_CONSUMER_CONTROL, + REPORT_ID_MOUSE, + REPORT_ID_GAMEPAD +}; + +uint8_t const hid_report_descriptor[] = +{ + //------------- Keyboard Report -------------// + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), + HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ), + HID_COLLECTION ( HID_COLLECTION_APPLICATION ), + HID_REPORT_ID ( REPORT_ID_KEYBOARD ), + HID_USAGE_PAGE( HID_USAGE_PAGE_KEYBOARD ), + // 8 bits Modifier Keys (Shfit, Control, Alt) + HID_USAGE_MIN ( 224 ), + HID_USAGE_MAX ( 231 ), + HID_LOGICAL_MIN ( 0 ), + HID_LOGICAL_MAX ( 1 ), + + HID_REPORT_COUNT ( 8 ), + HID_REPORT_SIZE ( 1 ), + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), + + // 8 bit reserved + HID_REPORT_COUNT ( 1 ), + HID_REPORT_SIZE ( 8 ), + HID_INPUT ( HID_CONSTANT ), + + // 6-byte Keycodes + HID_USAGE_PAGE (HID_USAGE_PAGE_KEYBOARD), + HID_USAGE_MIN ( 0 ), + HID_USAGE_MAX ( 255 ), + HID_LOGICAL_MIN ( 0 ), + HID_LOGICAL_MAX ( 255 ), + + HID_REPORT_COUNT ( 6 ), + HID_REPORT_SIZE ( 8 ), + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ), + + // LED Indicator Kana | Compose | Scroll Lock | CapsLock | NumLock + HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ), + /* 5-bit Led report */ + HID_USAGE_MIN ( 1 ), + HID_USAGE_MAX ( 5 ), + HID_REPORT_COUNT ( 5 ), + HID_REPORT_SIZE ( 1 ), + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), + /* led padding */ + HID_REPORT_COUNT ( 1 ), + HID_REPORT_SIZE ( 3 ), + HID_OUTPUT ( HID_CONSTANT ), + HID_COLLECTION_END, + + //------------- Consumer Control Report -------------// + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), + HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ), + HID_COLLECTION ( HID_COLLECTION_APPLICATION ), + HID_REPORT_ID( REPORT_ID_CONSUMER_CONTROL ), + HID_LOGICAL_MIN ( 0x00 ), + HID_LOGICAL_MAX_N( 0x03FF, 2 ), + HID_USAGE_MIN ( 0x00 ), + HID_USAGE_MAX_N ( 0x03FF, 2 ), + HID_REPORT_COUNT ( 1 ), + HID_REPORT_SIZE ( 16 ), + HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ), + HID_COLLECTION_END, + + //------------- Mouse Report: buttons + dx + dy + scroll + pan -------------// + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ), + HID_COLLECTION ( HID_COLLECTION_APPLICATION ), + HID_REPORT_ID( REPORT_ID_MOUSE ), + HID_USAGE (HID_USAGE_DESKTOP_POINTER ), + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ), + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ), + HID_USAGE_MIN ( 1 ), + HID_USAGE_MAX ( 5 ), + HID_LOGICAL_MIN ( 0 ), + HID_LOGICAL_MAX ( 1 ), + + HID_REPORT_COUNT ( 5 ), /* Forward, Backward, Middle, Right, Left */ + HID_REPORT_SIZE ( 1 ), + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), + + HID_REPORT_COUNT ( 1 ), + HID_REPORT_SIZE ( 3 ), + HID_INPUT ( HID_CONSTANT ), /* 5 bit padding followed 3 bit buttons */ + + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), + HID_USAGE ( HID_USAGE_DESKTOP_X ), + HID_USAGE ( HID_USAGE_DESKTOP_Y ), + HID_LOGICAL_MIN ( 0x81 ), /* -127 */ + HID_LOGICAL_MAX ( 0x7f ), /* 127 */ + + HID_REPORT_COUNT ( 2 ), /* X, Y position */ + HID_REPORT_SIZE ( 8 ), + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */ + + HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ), /* mouse scroll */ + HID_LOGICAL_MIN ( 0x81 ), /* -127 */ + HID_LOGICAL_MAX ( 0x7f ), /* 127 */ + HID_REPORT_COUNT( 1 ), + HID_REPORT_SIZE ( 8 ), /* 8-bit value */ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */ + + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), /* Horizontal wheel scroll */ + HID_LOGICAL_MIN ( 0x81 ), /* -127 */ + HID_LOGICAL_MAX ( 0x7f ), /* 127 */ + HID_REPORT_COUNT( 1 ), + HID_REPORT_SIZE ( 8 ), /* 8-bit value */ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), /* relative values */ + HID_COLLECTION_END, + HID_COLLECTION_END, + +#if 0 + //------------- Gamepad Report -------------// + /* Byte 0: 4 pad | 2 Y-axis | 2 X-axis + * Byte 1: Button7-Button0 + */ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), + HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ), + HID_COLLECTION ( HID_COLLECTION_APPLICATION ), + HID_REPORT_ID ( REPORT_ID_GAMEPAD ), + HID_USAGE (HID_USAGE_DESKTOP_POINTER ), + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ), + // X,Y joystick + HID_USAGE ( HID_USAGE_DESKTOP_X ), + HID_USAGE ( HID_USAGE_DESKTOP_Y ), + HID_LOGICAL_MIN ( 0xFF ), /* -1 */ + HID_LOGICAL_MAX ( 0x01 ), /* 1 */ + HID_REPORT_COUNT( 2 ), /* X, Y position */ + HID_REPORT_SIZE ( 2 ), /* 2-bit value */ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), /* input values */ + HID_COLLECTION_END, + + /* X,Y padding */ + HID_REPORT_COUNT ( 4 ), + HID_REPORT_SIZE ( 1 ), + HID_INPUT ( HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), + + // Buttons + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ), + HID_USAGE_MIN ( 1 ), + HID_USAGE_MAX ( 8 ), + HID_LOGICAL_MIN ( 0 ), + HID_LOGICAL_MAX ( 1 ), + HID_REPORT_COUNT ( 8 ), // Keyboard + HID_REPORT_SIZE ( 1 ), + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE), + HID_COLLECTION_END +#endif +}; + +BLEHidAdafruit::BLEHidAdafruit(void) + : BLEHidGeneric(3, 1, 0) +{ + _mse_buttons = 0; + _kbd_led_cb = NULL; +} + +err_t BLEHidAdafruit::begin(void) +{ + uint16_t input_len [] = { sizeof(hid_keyboard_report_t), sizeof(hid_consumer_control_report_t), sizeof(hid_mouse_report_t) }; + uint16_t output_len[] = { 1 }; + + setReportLen(input_len, output_len, NULL); + enableKeyboard(true); + enableMouse(true); + setReportMap(hid_report_descriptor, sizeof(hid_report_descriptor)); + + VERIFY_STATUS( BLEHidGeneric::begin() ); + + // Attempt to change the connection interval to 11.25-15 ms when starting HID + Bluefruit.setConnInterval(9, 12); + + return ERROR_NONE; +} + +/*------------------------------------------------------------------*/ +/* Keyboard + *------------------------------------------------------------------*/ + +void blehid_ada_keyboard_output_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset) +{ + LOG_LV2("HID", "Keyboard LED : 0x%02X", data[0]); + VERIFY(len == 1, ); + + BLEHidAdafruit& svc = (BLEHidAdafruit&) chr.parentService(); + if ( svc._kbd_led_cb ) svc._kbd_led_cb(data[0]); +} + +void BLEHidAdafruit::setKeyboardLedCallback(kbd_led_cb_t fp) +{ + _kbd_led_cb = fp; + + // Report mode + this->setOutputReportCallback(REPORT_ID_KEYBOARD, fp ? blehid_ada_keyboard_output_cb : NULL); + + // Boot mode + _chr_boot_keyboard_output->setWriteCallback(fp ? blehid_ada_keyboard_output_cb : NULL); +} + +bool BLEHidAdafruit::keyboardReport(hid_keyboard_report_t* report) +{ + if ( isBootMode() ) + { + return bootKeyboardReport(report, sizeof(hid_keyboard_report_t)); + }else + { + return inputReport( REPORT_ID_KEYBOARD, report, sizeof(hid_keyboard_report_t)); + } +} + +bool BLEHidAdafruit::keyboardReport(uint8_t modifier, uint8_t keycode[6]) +{ + hid_keyboard_report_t report = + { + .modifier = modifier, + }; + memcpy(report.keycode, keycode, 6); + + return keyboardReport(&report); +} + +bool BLEHidAdafruit::keyboardReport(uint8_t modifier, uint8_t keycode0, uint8_t keycode1, uint8_t keycode2, uint8_t keycode3, uint8_t keycode4, uint8_t keycode5) +{ + hid_keyboard_report_t report = + { + .modifier = modifier, + .reserved = 0, + .keycode = { keycode0, keycode1, keycode2, keycode3, keycode4, keycode5 } + }; + + return keyboardReport(&report); +} + +bool BLEHidAdafruit::keyPress(char ch) +{ + hid_keyboard_report_t report; + varclr(&report); + + report.modifier = ( HID_ASCII_TO_KEYCODE[(uint8_t)ch].shift ) ? KEYBOARD_MODIFIER_LEFTSHIFT : 0; + report.keycode[0] = HID_ASCII_TO_KEYCODE[(uint8_t)ch].keycode; + + return keyboardReport(&report); +} + +bool BLEHidAdafruit::keyRelease(void) +{ + hid_keyboard_report_t report; + varclr(&report); + + return keyboardReport(&report); +} + +bool BLEHidAdafruit::keySequence(const char* str, int interal) +{ + // Send each key in sequence + char ch; + while( (ch = *str++) != 0 ) + { + char lookahead = *str; + + keyPress(ch); + delay(interal); + + /* Only need to empty report if the next character is NULL or the same with + * the current one, else no need to send */ + if ( lookahead == ch || lookahead == 0 ) + { + keyRelease(); + delay(interal); + } + } + + return true; +} + +/*------------------------------------------------------------------*/ +/* Consumer Media Key + *------------------------------------------------------------------*/ +bool BLEHidAdafruit::consumerReport(uint16_t usage_code) +{ + return inputReport( REPORT_ID_CONSUMER_CONTROL, &usage_code, sizeof(usage_code)); +} + +bool BLEHidAdafruit::consumerKeyPress(uint16_t usage_code) +{ + return consumerReport(usage_code); +} + +bool BLEHidAdafruit::consumerKeyRelease(void) +{ + uint16_t usage = 0; + return consumerReport(usage); +} + +/*------------------------------------------------------------------*/ +/* Mouse + *------------------------------------------------------------------*/ +bool BLEHidAdafruit::mouseReport(hid_mouse_report_t* report) +{ + if ( isBootMode() ) + { + return bootMouseReport(report, sizeof(hid_mouse_report_t)); + }else + { + return inputReport( REPORT_ID_MOUSE, report, sizeof(hid_mouse_report_t)); + } +} + +bool BLEHidAdafruit::mouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel, int8_t pan) +{ + hid_mouse_report_t report = + { + .buttons = buttons, + .x = x, + .y = y, + .wheel = wheel, + .pan = pan + }; + + _mse_buttons = buttons; + + return mouseReport(&report); +} + +bool BLEHidAdafruit::mouseButtonPress(uint8_t buttons) +{ + _mse_buttons = buttons; + return mouseReport(buttons, 0, 0, 0, 0); +} + +bool BLEHidAdafruit::mouseButtonRelease(void) +{ + return mouseReport(0, 0, 0, 0, 0); +} + +bool BLEHidAdafruit::mouseMove(int8_t x, int8_t y) +{ + return mouseReport(_mse_buttons, x, y, 0, 0); +} + +bool BLEHidAdafruit::mouseScroll(int8_t scroll) +{ + return mouseReport(_mse_buttons, 0, 0, scroll, 0); +} + +bool BLEHidAdafruit::mousePan(int8_t pan) +{ + return mouseReport(_mse_buttons, 0, 0, 0, pan); +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h new file mode 100755 index 0000000..6563705 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidAdafruit.h @@ -0,0 +1,90 @@ +/**************************************************************************/ +/*! + @file BLEHidAdafruit.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEHIDADAFRUIT_H_ +#define BLEHIDADAFRUIT_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEHidGeneric.h" +#include "BLEService.h" + + +class BLEHidAdafruit : public BLEHidGeneric +{ + public: + /*--------- Callback Signatures ----------*/ + typedef void (*kbd_led_cb_t) (uint8_t leds_bitmap); + + BLEHidAdafruit(void); + + virtual err_t begin(void); + + // Keyboard + bool keyboardReport(hid_keyboard_report_t* report); + bool keyboardReport(uint8_t modifier, uint8_t keycode[6]); + bool keyboardReport(uint8_t modifier, uint8_t keycode0, uint8_t keycode1=0, uint8_t keycode2=0, uint8_t keycode3=0, uint8_t keycode4=0, uint8_t keycode5=0); + + void setKeyboardLedCallback(kbd_led_cb_t fp); + + bool keyPress(char ch); + bool keyRelease(void); + bool keySequence(const char* str, int interal=5); + + // Consumer Media Keys + bool consumerReport(uint16_t usage_code); + bool consumerKeyPress(uint16_t usage_code); + bool consumerKeyRelease(void); + + // Mouse + bool mouseReport(hid_mouse_report_t* report); + bool mouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel=0, int8_t pan=0); + + bool mouseButtonPress(uint8_t buttons); + bool mouseButtonRelease(void); + + bool mouseMove(int8_t x, int8_t y); + bool mouseScroll(int8_t scroll); + bool mousePan(int8_t pan); + + protected: + uint8_t _mse_buttons; + kbd_led_cb_t _kbd_led_cb; + + friend void blehid_ada_keyboard_output_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset); +}; + +#endif /* BLEHIDADAFRUIT_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp new file mode 100755 index 0000000..a95ddc2 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.cpp @@ -0,0 +1,516 @@ +/**************************************************************************/ +/*! + @file BLEHidGeneric.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +enum { + REPORT_TYPE_INPUT = 1, + REPORT_TYPE_OUTPUT, + REPORT_TYPE_FEATURE +}; + +BLEHidGeneric::BLEHidGeneric(uint8_t num_input, uint8_t num_output, uint8_t num_feature) + : BLEService(UUID16_SVC_HUMAN_INTERFACE_DEVICE), _chr_control(UUID16_CHR_HID_CONTROL_POINT) +{ + _has_keyboard = _has_mouse = false; + _protocol_mode = HID_PROTOCOL_MODE_REPORT; + + _report_map = NULL; + _report_map_len = 0; + + _input_len = _output_len = _feature_len = NULL; + + _num_input = num_input; + _num_output = num_output; + _num_feature = num_feature; + + // HID Information + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hid_information.xml + // bcd 1.1, country = 0, flag = normal connect + _hid_info[0] = 0x01; + _hid_info[1] = 0x01; + _hid_info[2] = 0x00; + _hid_info[3] = bit(1); + + _chr_protocol = NULL; + _chr_inputs = _chr_outputs = _chr_features = NULL; + _chr_boot_keyboard_input = _chr_boot_keyboard_output = _chr_boot_mouse_input = NULL; + + if ( _num_input ) + { + _chr_inputs = new BLECharacteristic[_num_input]; + } + + if ( _num_output ) + { + _chr_outputs = new BLECharacteristic[_num_output]; + } + + if ( _num_feature ) + { + _chr_features = new BLECharacteristic[_num_feature]; + } +} + +/*------------------------------------------------------------------*/ +/* CONFIG + *------------------------------------------------------------------*/ +void BLEHidGeneric::enableKeyboard(bool enable) +{ + _has_keyboard = enable; +} + +void BLEHidGeneric::enableMouse(bool enable) +{ + _has_mouse = enable; +} + +void BLEHidGeneric::setHidInfo(uint16_t bcd, uint8_t country, uint8_t flags) +{ + memcpy(_hid_info, &bcd, 2); + _hid_info[2] = country; + _hid_info[3] = flags; +} + +void BLEHidGeneric::setReportMap(const uint8_t* report_map, size_t len) +{ + _report_map = report_map; + _report_map_len = len; +} + +void BLEHidGeneric::setReportLen(uint16_t input_len[], uint16_t output_len[], uint16_t feature_len[]) +{ + _input_len = input_len; + _output_len = output_len; + _feature_len = feature_len; +} + +void BLEHidGeneric::setOutputReportCallback(uint8_t reportID, BLECharacteristic::write_cb_t fp) +{ + // index is ID-1 + uint8_t const idx = ( reportID ? (reportID-1) : 0 ); + + // report mode + if ( idx < _num_output ) _chr_outputs[idx].setWriteCallback(fp); +} + +/*------------------------------------------------------------------*/ +/* Callbacks + *------------------------------------------------------------------*/ +void blehid_generic_protocol_mode_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset) +{ + BLEHidGeneric& svc = (BLEHidGeneric&) chr.parentService(); + svc._protocol_mode = *data; + + LOG_LV2("HID", "Protocol Mode : %d (0 Boot, 1 Report)", *data); +} + +/*------------------------------------------------------------------*/ +/* Begin + *------------------------------------------------------------------*/ +err_t BLEHidGeneric::begin(void) +{ + VERIFY ( (_report_map != NULL) && _report_map_len, NRF_ERROR_INVALID_PARAM); + + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + // Protocol Mode + if ( _has_keyboard || _has_mouse ) + { + _chr_protocol = new BLECharacteristic(UUID16_CHR_PROTOCOL_MODE); + VERIFY(_chr_protocol, NRF_ERROR_NO_MEM); + + _chr_protocol->setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE_WO_RESP); + _chr_protocol->setFixedLen(1); + _chr_protocol->setWriteCallback(blehid_generic_protocol_mode_cb); + VERIFY_STATUS( _chr_protocol->begin() ); + _chr_protocol->write8(_protocol_mode); + } + + // Input reports + for(uint8_t i=0; i<_num_input; i++) + { + _chr_inputs[i].setUuid(UUID16_CHR_REPORT); + _chr_inputs[i].setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); + _chr_inputs[i].setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS); + _chr_inputs[i].setReportRefDescriptor(i+1, REPORT_TYPE_INPUT); + + // Input report len is configured, else variable len up to 255 + if ( _input_len ) _chr_inputs[i].setFixedLen( _input_len[i] ); + + VERIFY_STATUS( _chr_inputs[i].begin() ); + } + + // Output reports + for(uint8_t i=0; i<_num_output; i++) + { + _chr_outputs[i].setUuid(UUID16_CHR_REPORT); + _chr_outputs[i].setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP); + _chr_outputs[i].setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM); + _chr_outputs[i].setReportRefDescriptor(i+1, REPORT_TYPE_OUTPUT); + + // Input report len is configured, else variable len up to 255 + if ( _output_len ) _chr_outputs[i].setFixedLen( _output_len[i] ); + + VERIFY_STATUS( _chr_outputs[i].begin() ); + + _chr_outputs[i].write8(0); + } + + // Report Map (HID Report Descriptor) + BLECharacteristic report_map(UUID16_CHR_REPORT_MAP); + report_map.setTempMemory(); + report_map.setProperties(CHR_PROPS_READ); + report_map.setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS); + report_map.setFixedLen(_report_map_len); + VERIFY_STATUS( report_map.begin() ); + report_map.write(_report_map, _report_map_len); + + // Boot Keyboard Input & Output Report + if ( _has_keyboard ) + { + _chr_boot_keyboard_input = new BLECharacteristic(UUID16_CHR_BOOT_KEYBOARD_INPUT_REPORT); + _chr_boot_keyboard_input->setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); + _chr_boot_keyboard_input->setFixedLen(8); // boot keyboard is 8 bytes + _chr_boot_keyboard_input->setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS); + VERIFY_STATUS(_chr_boot_keyboard_input->begin()); + + _chr_boot_keyboard_output = new BLECharacteristic(UUID16_CHR_BOOT_KEYBOARD_OUTPUT_REPORT); + _chr_boot_keyboard_output->setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP); + _chr_boot_keyboard_output->setFixedLen(1); // boot keyboard is 1 byte + _chr_boot_keyboard_output->setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM); + VERIFY_STATUS(_chr_boot_keyboard_output->begin()); + _chr_boot_keyboard_output->write8(0); + } + + // Boot Mouse Input Report + if ( _has_mouse ) + { + _chr_boot_mouse_input = new BLECharacteristic(UUID16_CHR_BOOT_MOUSE_INPUT_REPORT); + _chr_boot_mouse_input->setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); + _chr_boot_mouse_input->setFixedLen(sizeof(hid_mouse_report_t)); + _chr_boot_mouse_input->setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS); + VERIFY_STATUS(_chr_boot_mouse_input->begin()); + } + + // HID Info + BLECharacteristic hid_info(UUID16_CHR_HID_INFORMATION); + hid_info.setTempMemory(); + hid_info.setProperties(CHR_PROPS_READ); + hid_info.setPermission(SECMODE_ENC_NO_MITM, SECMODE_NO_ACCESS); + hid_info.setFixedLen(sizeof(_hid_info)); + VERIFY_STATUS( hid_info.begin() ); + hid_info.write(_hid_info, sizeof(_hid_info)); + + // HID Control Point + _chr_control.setProperties(CHR_PROPS_WRITE_WO_RESP); + _chr_control.setPermission(SECMODE_NO_ACCESS, SECMODE_ENC_NO_MITM); + _chr_control.setFixedLen(1); + VERIFY_STATUS( _chr_control.begin() ); + _chr_control.write8(0); + + return ERROR_NONE; +} + +/*------------------------------------------------------------------*/ +/* Input Report + *------------------------------------------------------------------*/ +bool BLEHidGeneric::inputReport(uint8_t reportID, void const* data, int len) +{ + // index is ID-1 + uint8_t const idx = ( reportID ? (reportID-1) : 0 ); + + return _chr_inputs[idx].notify( (uint8_t const*) data, len); +} + +bool BLEHidGeneric::bootKeyboardReport(void const* data, int len) +{ + return _chr_boot_keyboard_input->notify(data, len); +} + +bool BLEHidGeneric::bootMouseReport(void const* data, int len) +{ + return _chr_boot_mouse_input->notify(data, len); +} + +/*------------------------------------------------------------------*/ +/* Ascii to Keycode + *------------------------------------------------------------------*/ +const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128] = +{ + {0, 0 }, // 0x00 Null + {0, 0 }, // 0x01 + {0, 0 }, // 0x02 + {0, 0 }, // 0x03 + {0, 0 }, // 0x04 + {0, 0 }, // 0x05 + {0, 0 }, // 0x06 + {0, 0 }, // 0x07 + {0, HID_KEY_BACKSPACE }, // 0x08 Backspace + {0, HID_KEY_TAB }, // 0x09 Horizontal Tab + {0, HID_KEY_RETURN }, // 0x0A Line Feed + {0, 0 }, // 0x0B + {0, 0 }, // 0x0C + {0, HID_KEY_RETURN }, // 0x0D Carriage return + {0, 0 }, // 0x0E + {0, 0 }, // 0x0F + {0, 0 }, // 0x10 + {0, 0 }, // 0x11 + {0, 0 }, // 0x12 + {0, 0 }, // 0x13 + {0, 0 }, // 0x14 + {0, 0 }, // 0x15 + {0, 0 }, // 0x16 + {0, 0 }, // 0x17 + {0, 0 }, // 0x18 + {0, 0 }, // 0x19 + {0, 0 }, // 0x1A + {0, HID_KEY_ESCAPE }, // 0x1B Escape + {0, 0 }, // 0x1C + {0, 0 }, // 0x1D + {0, 0 }, // 0x1E + {0, 0 }, // 0x1F + + {0, HID_KEY_SPACE }, // 0x20 + {1, HID_KEY_1 }, // 0x21 ! + {1, HID_KEY_APOSTROPHE }, // 0x22 " + {1, HID_KEY_3 }, // 0x23 # + {1, HID_KEY_4 }, // 0x24 $ + {1, HID_KEY_5 }, // 0x25 % + {1, HID_KEY_7 }, // 0x26 & + {0, HID_KEY_APOSTROPHE }, // 0x27 ' + {1, HID_KEY_9 }, // 0x28 ( + {1, HID_KEY_0 }, // 0x29 ) + {1, HID_KEY_8 }, // 0x2A * + {1, HID_KEY_EQUAL }, // 0x2B + + {0, HID_KEY_COMMA }, // 0x2C , + {0, HID_KEY_MINUS }, // 0x2D - + {0, HID_KEY_PERIOD }, // 0x2E . + {0, HID_KEY_SLASH }, // 0x2F / + {0, HID_KEY_0 }, // 0x30 0 + {0, HID_KEY_1 }, // 0x31 1 + {0, HID_KEY_2 }, // 0x32 2 + {0, HID_KEY_3 }, // 0x33 3 + {0, HID_KEY_4 }, // 0x34 4 + {0, HID_KEY_5 }, // 0x35 5 + {0, HID_KEY_6 }, // 0x36 6 + {0, HID_KEY_7 }, // 0x37 7 + {0, HID_KEY_8 }, // 0x38 8 + {0, HID_KEY_9 }, // 0x39 9 + {1, HID_KEY_SEMICOLON }, // 0x3A : + {0, HID_KEY_SEMICOLON }, // 0x3B ; + {1, HID_KEY_COMMA }, // 0x3C < + {0, HID_KEY_EQUAL }, // 0x3D = + {1, HID_KEY_PERIOD }, // 0x3E > + {1, HID_KEY_SLASH }, // 0x3F ? + + {1, HID_KEY_2 }, // 0x40 @ + {1, HID_KEY_A }, // 0x41 A + {1, HID_KEY_B }, // 0x42 B + {1, HID_KEY_C }, // 0x43 C + {1, HID_KEY_D }, // 0x44 D + {1, HID_KEY_E }, // 0x45 E + {1, HID_KEY_F }, // 0x46 F + {1, HID_KEY_G }, // 0x47 G + {1, HID_KEY_H }, // 0x48 H + {1, HID_KEY_I }, // 0x49 I + {1, HID_KEY_J }, // 0x4A J + {1, HID_KEY_K }, // 0x4B K + {1, HID_KEY_L }, // 0x4C L + {1, HID_KEY_M }, // 0x4D M + {1, HID_KEY_N }, // 0x4E N + {1, HID_KEY_O }, // 0x4F O + {1, HID_KEY_P }, // 0x50 P + {1, HID_KEY_Q }, // 0x51 Q + {1, HID_KEY_R }, // 0x52 R + {1, HID_KEY_S }, // 0x53 S + {1, HID_KEY_T }, // 0x55 T + {1, HID_KEY_U }, // 0x55 U + {1, HID_KEY_V }, // 0x56 V + {1, HID_KEY_W }, // 0x57 W + {1, HID_KEY_X }, // 0x58 X + {1, HID_KEY_Y }, // 0x59 Y + {1, HID_KEY_Z }, // 0x5A Z + {0, HID_KEY_BRACKET_LEFT }, // 0x5B [ + {0, HID_KEY_BACKSLASH }, // 0x5C '\' + {0, HID_KEY_BRACKET_RIGHT }, // 0x5D ] + {1, HID_KEY_6 }, // 0x5E ^ + {1, HID_KEY_MINUS }, // 0x5F _ + + {0, HID_KEY_GRAVE }, // 0x60 ` + {0, HID_KEY_A }, // 0x61 a + {0, HID_KEY_B }, // 0x62 b + {0, HID_KEY_C }, // 0x63 c + {0, HID_KEY_D }, // 0x66 d + {0, HID_KEY_E }, // 0x65 e + {0, HID_KEY_F }, // 0x66 f + {0, HID_KEY_G }, // 0x67 g + {0, HID_KEY_H }, // 0x68 h + {0, HID_KEY_I }, // 0x69 i + {0, HID_KEY_J }, // 0x6A j + {0, HID_KEY_K }, // 0x6B k + {0, HID_KEY_L }, // 0x6C l + {0, HID_KEY_M }, // 0x6D m + {0, HID_KEY_N }, // 0x6E n + {0, HID_KEY_O }, // 0x6F o + {0, HID_KEY_P }, // 0x70 p + {0, HID_KEY_Q }, // 0x71 q + {0, HID_KEY_R }, // 0x72 r + {0, HID_KEY_S }, // 0x73 s + {0, HID_KEY_T }, // 0x75 t + {0, HID_KEY_U }, // 0x75 u + {0, HID_KEY_V }, // 0x76 v + {0, HID_KEY_W }, // 0x77 w + {0, HID_KEY_X }, // 0x78 x + {0, HID_KEY_Y }, // 0x79 y + {0, HID_KEY_Z }, // 0x7A z + {1, HID_KEY_BRACKET_LEFT }, // 0x7B { + {1, HID_KEY_BACKSLASH }, // 0x7C | + {1, HID_KEY_BRACKET_RIGHT }, // 0x7D } + {1, HID_KEY_GRAVE }, // 0x7E ~ + {0, HID_KEY_DELETE } // 0x7F Delete +}; + +/*------------------------------------------------------------------*/ +/* Keycode to Ascii + *------------------------------------------------------------------*/ +const hid_keycode_to_ascii_t HID_KEYCODE_TO_ASCII[128] = +{ + {0 , 0 }, // 0x00 + {0 , 0 }, // 0x01 + {0 , 0 }, // 0x02 + {0 , 0 }, // 0x03 + {'a' , 'A' }, // 0x04 + {'b' , 'B' }, // 0x05 + {'c' , 'C' }, // 0x06 + {'d' , 'D' }, // 0x07 + {'e' , 'E' }, // 0x08 + {'f' , 'F' }, // 0x09 + {'g' , 'G' }, // 0x0a + {'h' , 'H' }, // 0x0b + {'i' , 'I' }, // 0x0c + {'j' , 'J' }, // 0x0d + {'k' , 'K' }, // 0x0e + {'l' , 'L' }, // 0x0f + {'m' , 'M' }, // 0x10 + {'n' , 'N' }, // 0x11 + {'o' , 'O' }, // 0x12 + {'p' , 'P' }, // 0x13 + {'q' , 'Q' }, // 0x14 + {'r' , 'R' }, // 0x15 + {'s' , 'S' }, // 0x16 + {'t' , 'T' }, // 0x17 + {'u' , 'U' }, // 0x18 + {'v' , 'V' }, // 0x19 + {'w' , 'W' }, // 0x1a + {'x' , 'X' }, // 0x1b + {'y' , 'Y' }, // 0x1c + {'z' , 'Z' }, // 0x1d + {'1' , '!' }, // 0x1e + {'2' , '@' }, // 0x1f + {'3' , '#' }, // 0x20 + {'4' , '$' }, // 0x21 + {'5' , '%' }, // 0x22 + {'6' , '^' }, // 0x23 + {'7' , '&' }, // 0x24 + {'8' , '*' }, // 0x25 + {'9' , '(' }, // 0x26 + {'0' , ')' }, // 0x27 + {'\r' , '\r' }, // 0x28 + {'\x1b', '\x1b' }, // 0x29 + {'\b' , '\b' }, // 0x2a + {'\t' , '\t' }, // 0x2b + {' ' , ' ' }, // 0x2c + {'-' , '_' }, // 0x2d + {'=' , '+' }, // 0x2e + {'[' , '{' }, // 0x2f + {']' , '}' }, // 0x30 + {'\\' , '|' }, // 0x31 + {'#' , '~' }, // 0x32 + {';' , ':' }, // 0x33 + {'\'' , '\"' }, // 0x34 + {0 , 0 }, // 0x35 + {',' , '<' }, // 0x36 + {'.' , '>' }, // 0x37 + {'/' , '?' }, // 0x38 + + {0 , 0 }, // 0x39 + {0 , 0 }, // 0x3a + {0 , 0 }, // 0x3b + {0 , 0 }, // 0x3c + {0 , 0 }, // 0x3d + {0 , 0 }, // 0x3e + {0 , 0 }, // 0x3f + {0 , 0 }, // 0x40 + {0 , 0 }, // 0x41 + {0 , 0 }, // 0x42 + {0 , 0 }, // 0x43 + {0 , 0 }, // 0x44 + {0 , 0 }, // 0x45 + {0 , 0 }, // 0x46 + {0 , 0 }, // 0x47 + {0 , 0 }, // 0x48 + {0 , 0 }, // 0x49 + {0 , 0 }, // 0x4a + {0 , 0 }, // 0x4b + {0 , 0 }, // 0x4c + {0 , 0 }, // 0x4d + {0 , 0 }, // 0x4e + {0 , 0 }, // 0x4f + {0 , 0 }, // 0x50 + {0 , 0 }, // 0x51 + {0 , 0 }, // 0x52 + {0 , 0 }, // 0x53 + + {'/' , '/' }, // 0x54 + {'*' , '*' }, // 0x55 + {'-' , '-' }, // 0x56 + {'+' , '+' }, // 0x57 + {'\r' , '\r' }, // 0x58 + {'1' , 0 }, // 0x59 /* numpad1 & end */ \ + {'2' , 0 }, // 0x5a + {'3' , 0 }, // 0x5b + {'4' , 0 }, // 0x5c + {'5' , '5' }, // 0x5d + {'6' , 0 }, // 0x5e + {'7' , 0 }, // 0x5f + {'8' , 0 }, // 0x60 + {'9' , 0 }, // 0x61 + {'0' , 0 }, // 0x62 + {'0' , 0 }, // 0x63 + {'=' , '=' }, // 0x67 +}; diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h new file mode 100755 index 0000000..449668a --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEHidGeneric.h @@ -0,0 +1,583 @@ +/**************************************************************************/ +/*! + @file BLEHidGeneric.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEHIDGENERIC_H_ +#define BLEHIDGENERIC_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +enum +{ + HID_PROTOCOL_MODE_BOOT = 0, + HID_PROTOCOL_MODE_REPORT = 1 +}; + +typedef struct{ + uint8_t shift; + uint8_t keycode; +}hid_ascii_to_keycode_entry_t; +extern const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128]; + +typedef struct{ + uint8_t ascii; + uint8_t shifted; +}hid_keycode_to_ascii_t; +extern hid_keycode_to_ascii_t const HID_KEYCODE_TO_ASCII[128]; + +/// Standard HID Boot Protocol Mouse Report. +typedef ATTR_PACKED_STRUCT(struct) +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int8_t x; /**< Current delta x movement of the mouse. */ + int8_t y; /**< Current delta y movement on the mouse. */ + int8_t wheel; /**< Current delta vertical wheel movement on the mouse. */ + int8_t pan; /**< Current delta horizontal wheel movement on the mouse. */ +} hid_mouse_report_t; + +/// Standard HID Boot Protocol Keyboard Report. +typedef ATTR_PACKED_STRUCT(struct) +{ + uint8_t modifier; /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of HID_KEYBOARD_MODIFER_* masks). */ + uint8_t reserved; /**< Reserved for OEM use, always set to 0. */ + uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */ +} hid_keyboard_report_t; + +/// HID Consumer Control Report +typedef ATTR_PACKED_STRUCT(struct) +{ + uint16_t usage_value; ///< Usage value of the pressed control +} hid_consumer_control_report_t; + +/// Gamepad report +typedef ATTR_PACKED_STRUCT(struct) +{ + ATTR_PACKED_STRUCT(struct){ + uint8_t x : 2; + uint8_t y : 2; + uint8_t : 4; + }; + + uint8_t buttons; +}hid_gamepad_report_t; + + +class BLEHidGeneric : public BLEService +{ + public: + BLEHidGeneric(uint8_t num_input, uint8_t num_output = 0, uint8_t num_feature = 0); + + void enableKeyboard(bool enable); + void enableMouse(bool enable); + + void setHidInfo(uint16_t bcd, uint8_t country, uint8_t flags); + + void setReportLen(uint16_t input_len[], uint16_t output_len[] = NULL, uint16_t feature_len[] = NULL); + void setReportMap(const uint8_t* report_map, size_t len); + + void setOutputReportCallback(uint8_t reportID, BLECharacteristic::write_cb_t fp); + + virtual err_t begin(void); + + bool isBootMode(void) { return _protocol_mode == HID_PROTOCOL_MODE_BOOT; } + + // Report + bool inputReport(uint8_t reportID, void const* data, int len); + bool bootKeyboardReport(void const* data, int len); + bool bootMouseReport(void const* data, int len); + + protected: + uint8_t _num_input; + uint8_t _num_output; + uint8_t _num_feature; + + bool _has_keyboard; + bool _has_mouse; + bool _protocol_mode; + + uint8_t _hid_info[4]; + const uint8_t* _report_map; + size_t _report_map_len; + + uint16_t* _input_len; + uint16_t* _output_len; + uint16_t* _feature_len; + + BLECharacteristic* _chr_protocol; + + BLECharacteristic* _chr_inputs; + BLECharacteristic* _chr_outputs; + BLECharacteristic* _chr_features; + + BLECharacteristic* _chr_boot_keyboard_input; + BLECharacteristic* _chr_boot_keyboard_output; + BLECharacteristic* _chr_boot_mouse_input; + + BLECharacteristic _chr_control; + + friend void blehid_generic_protocol_mode_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset); +}; + +//--------------------------------------------------------------------+ +// MOUSE +//--------------------------------------------------------------------+ + +/// Standard Mouse Buttons Bitmap +typedef enum { + MOUSE_BUTTON_LEFT = bit(0), ///< Left button + MOUSE_BUTTON_RIGHT = bit(1), ///< Right button + MOUSE_BUTTON_MIDDLE = bit(2), ///< Middle button, + MOUSE_BUTTON_BACKWARD = bit(3), ///< Backward button, + MOUSE_BUTTON_FORWARD = bit(4), ///< Forward button, +}hid_mouse_button_bm_t; + +//--------------------------------------------------------------------+ +// Keyboard +//--------------------------------------------------------------------+ + +///// Keyboard modifier codes bitmap +typedef enum { + KEYBOARD_MODIFIER_LEFTCTRL = bit(0), ///< Left Control + KEYBOARD_MODIFIER_LEFTSHIFT = bit(1), ///< Left Shift + KEYBOARD_MODIFIER_LEFTALT = bit(2), ///< Left Alt + KEYBOARD_MODIFIER_LEFTGUI = bit(3), ///< Left Window + KEYBOARD_MODIFIER_RIGHTCTRL = bit(4), ///< Right Control + KEYBOARD_MODIFIER_RIGHTSHIFT = bit(5), ///< Right Shift + KEYBOARD_MODIFIER_RIGHTALT = bit(6), ///< Right Alt + KEYBOARD_MODIFIER_RIGHTGUI = bit(7) ///< Right Window +}hid_keyboard_modifier_bm_t; + +typedef enum { + KEYBOARD_LED_NUMLOCK = bit(0), ///< Num Lock LED + KEYBOARD_LED_CAPSLOCK = bit(1), ///< Caps Lock LED + KEYBOARD_LED_SCROLLLOCK = bit(2), ///< Scroll Lock LED + KEYBOARD_LED_COMPOSE = bit(3), ///< Composition Mode + KEYBOARD_LED_KANA = bit(4) ///< Kana mode +}hid_keyboard_led_bm_t; + +//--------------------------------------------------------------------+ +// HID KEYCODE +//--------------------------------------------------------------------+ +#define HID_KEY_NONE 0x00 +#define HID_KEY_A 0x04 +#define HID_KEY_B 0x05 +#define HID_KEY_C 0x06 +#define HID_KEY_D 0x07 +#define HID_KEY_E 0x08 +#define HID_KEY_F 0x09 +#define HID_KEY_G 0x0A +#define HID_KEY_H 0x0B +#define HID_KEY_I 0x0C +#define HID_KEY_J 0x0D +#define HID_KEY_K 0x0E +#define HID_KEY_L 0x0F +#define HID_KEY_M 0x10 +#define HID_KEY_N 0x11 +#define HID_KEY_O 0x12 +#define HID_KEY_P 0x13 +#define HID_KEY_Q 0x14 +#define HID_KEY_R 0x15 +#define HID_KEY_S 0x16 +#define HID_KEY_T 0x17 +#define HID_KEY_U 0x18 +#define HID_KEY_V 0x19 +#define HID_KEY_W 0x1A +#define HID_KEY_X 0x1B +#define HID_KEY_Y 0x1C +#define HID_KEY_Z 0x1D +#define HID_KEY_1 0x1E +#define HID_KEY_2 0x1F +#define HID_KEY_3 0x20 +#define HID_KEY_4 0x21 +#define HID_KEY_5 0x22 +#define HID_KEY_6 0x23 +#define HID_KEY_7 0x24 +#define HID_KEY_8 0x25 +#define HID_KEY_9 0x26 +#define HID_KEY_0 0x27 +#define HID_KEY_RETURN 0x28 +#define HID_KEY_ESCAPE 0x29 +#define HID_KEY_BACKSPACE 0x2A +#define HID_KEY_TAB 0x2B +#define HID_KEY_SPACE 0x2C +#define HID_KEY_MINUS 0x2D +#define HID_KEY_EQUAL 0x2E +#define HID_KEY_BRACKET_LEFT 0x2F +#define HID_KEY_BRACKET_RIGHT 0x30 +#define HID_KEY_BACKSLASH 0x31 +#define HID_KEY_EUROPE_1 0x32 +#define HID_KEY_SEMICOLON 0x33 +#define HID_KEY_APOSTROPHE 0x34 +#define HID_KEY_GRAVE 0x35 +#define HID_KEY_COMMA 0x36 +#define HID_KEY_PERIOD 0x37 +#define HID_KEY_SLASH 0x38 +#define HID_KEY_CAPS_LOCK 0x39 +#define HID_KEY_F1 0x3A +#define HID_KEY_F2 0x3B +#define HID_KEY_F3 0x3C +#define HID_KEY_F4 0x3D +#define HID_KEY_F5 0x3E +#define HID_KEY_F6 0x3F +#define HID_KEY_F7 0x40 +#define HID_KEY_F8 0x41 +#define HID_KEY_F9 0x42 +#define HID_KEY_F10 0x43 +#define HID_KEY_F11 0x44 +#define HID_KEY_F12 0x45 +#define HID_KEY_PRINT_SCREEN 0x46 +#define HID_KEY_SCROLL_LOCK 0x47 +#define HID_KEY_PAUSE 0x48 +#define HID_KEY_INSERT 0x49 +#define HID_KEY_HOME 0x4A +#define HID_KEY_PAGE_UP 0x4B +#define HID_KEY_DELETE 0x4C +#define HID_KEY_END 0x4D +#define HID_KEY_PAGE_DOWN 0x4E +#define HID_KEY_ARROW_RIGHT 0x4F +#define HID_KEY_ARROW_LEFT 0x50 +#define HID_KEY_ARROW_DOWN 0x51 +#define HID_KEY_ARROW_UP 0x52 +#define HID_KEY_NUM_LOCK 0x53 +#define HID_KEY_KEYPAD_DIVIDE 0x54 +#define HID_KEY_KEYPAD_MULTIPLY 0x55 +#define HID_KEY_KEYPAD_SUBTRACT 0x56 +#define HID_KEY_KEYPAD_ADD 0x57 +#define HID_KEY_KEYPAD_ENTER 0x58 +#define HID_KEY_KEYPAD_1 0x59 +#define HID_KEY_KEYPAD_2 0x5A +#define HID_KEY_KEYPAD_3 0x5B +#define HID_KEY_KEYPAD_4 0x5C +#define HID_KEY_KEYPAD_5 0x5D +#define HID_KEY_KEYPAD_6 0x5E +#define HID_KEY_KEYPAD_7 0x5F +#define HID_KEY_KEYPAD_8 0x60 +#define HID_KEY_KEYPAD_9 0x61 +#define HID_KEY_KEYPAD_0 0x62 +#define HID_KEY_KEYPAD_DECIMAL 0x63 +#define HID_KEY_EUROPE_2 0x64 +#define HID_KEY_APPLICATION 0x65 +#define HID_KEY_POWER 0x66 +#define HID_KEY_KEYPAD_EQUAL 0x67 +#define HID_KEY_F13 0x68 +#define HID_KEY_F14 0x69 +#define HID_KEY_F15 0x6A +#define HID_KEY_CONTROL_LEFT 0xE0 +#define HID_KEY_SHIFT_LEFT 0xE1 +#define HID_KEY_ALT_LEFT 0xE2 +#define HID_KEY_GUI_LEFT 0xE3 +#define HID_KEY_CONTROL_RIGHT 0xE4 +#define HID_KEY_SHIFT_RIGHT 0xE5 +#define HID_KEY_ALT_RIGHT 0xE6 +#define HID_KEY_GUI_RIGHT 0xE7 + +//--------------------------------------------------------------------+ +// REPORT DESCRIPTOR +//--------------------------------------------------------------------+ +//------------- ITEM & TAG -------------// +#define HID_REPORT_DATA_0(data) +#define HID_REPORT_DATA_1(data) , (data) +#define HID_REPORT_DATA_2(data) , U16_BYTES_LE(data) +#define HID_REPORT_DATA_3(data) , U32_BYTES_LE(data) + +#define HID_REPORT_ITEM(data, tag, type, size) \ + (((tag) << 4) | ((type) << 2) | (size)) HID_REPORT_DATA_##size(data) + +#define RI_TYPE_MAIN 0 +#define RI_TYPE_GLOBAL 1 +#define RI_TYPE_LOCAL 2 + +//------------- MAIN ITEMS 6.2.2.4 -------------// +#define HID_INPUT(x) HID_REPORT_ITEM(x, 8, RI_TYPE_MAIN, 1) +#define HID_OUTPUT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_MAIN, 1) +#define HID_COLLECTION(x) HID_REPORT_ITEM(x, 10, RI_TYPE_MAIN, 1) +#define HID_FEATURE(x) HID_REPORT_ITEM(x, 11, RI_TYPE_MAIN, 1) +#define HID_COLLECTION_END HID_REPORT_ITEM(x, 12, RI_TYPE_MAIN, 0) + +//------------- INPUT, OUTPUT, FEATURE 6.2.2.5 -------------// +#define HID_DATA (0<<0) +#define HID_CONSTANT (1<<0) + +#define HID_ARRAY (0<<1) +#define HID_VARIABLE (1<<1) + +#define HID_ABSOLUTE (0<<2) +#define HID_RELATIVE (1<<2) + +#define HID_WRAP_NO (0<<3) +#define HID_WRAP (1<<3) + +#define HID_LINEAR (0<<4) +#define HID_NONLINEAR (1<<4) + +#define HID_PREFERRED_STATE (0<<5) +#define HID_PREFERRED_NO (1<<5) + +#define HID_NO_NULL_POSITION (0<<6) +#define HID_NULL_STATE (1<<6) + +#define HID_NON_VOLATILE (0<<7) +#define HID_VOLATILE (1<<7) + +#define HID_BITFIELD (0<<8) +#define HID_BUFFERED_BYTES (1<<8) + +//------------- COLLECTION ITEM 6.2.2.6 -------------// +enum { + HID_COLLECTION_PHYSICAL = 0, + HID_COLLECTION_APPLICATION, + HID_COLLECTION_LOGICAL, + HID_COLLECTION_REPORT, + HID_COLLECTION_NAMED_ARRAY, + HID_COLLECTION_USAGE_SWITCH, + HID_COLLECTION_USAGE_MODIFIER +}; + +//------------- GLOBAL ITEMS 6.2.2.7 -------------// +#define HID_USAGE_PAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, 1) +#define HID_USAGE_PAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_GLOBAL, n) + +#define HID_LOGICAL_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, 1) +#define HID_LOGICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MIN(x) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MIN_N(x, n) HID_REPORT_ITEM(x, 3, RI_TYPE_GLOBAL, n) + +#define HID_PHYSICAL_MAX(x) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, 1) +#define HID_PHYSICAL_MAX_N(x, n) HID_REPORT_ITEM(x, 4, RI_TYPE_GLOBAL, n) + +#define HID_UNIT_EXPONENT(x) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_EXPONENT_N(x, n) HID_REPORT_ITEM(x, 5, RI_TYPE_GLOBAL, n) + +#define HID_UNIT(x) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, 1) +#define HID_UNIT_N(x, n) HID_REPORT_ITEM(x, 6, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_SIZE(x) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_SIZE_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_ID(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_ID_N(x) HID_REPORT_ITEM(x, 8, RI_TYPE_GLOBAL, n) + +#define HID_REPORT_COUNT(x) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, 1) +#define HID_REPORT_COUNT_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_GLOBAL, n) + +#define HID_PUSH HID_REPORT_ITEM(x, 10, RI_TYPE_GLOBAL, 0) +#define HID_POP HID_REPORT_ITEM(x, 11, RI_TYPE_GLOBAL, 0) + +//------------- LOCAL ITEMS 6.2.2.8 -------------// +#define HID_USAGE(x) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, 1) +#define HID_USAGE_N(x, n) HID_REPORT_ITEM(x, 0, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MIN(x) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MIN_N(x, n) HID_REPORT_ITEM(x, 1, RI_TYPE_LOCAL, n) + +#define HID_USAGE_MAX(x) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, 1) +#define HID_USAGE_MAX_N(x, n) HID_REPORT_ITEM(x, 2, RI_TYPE_LOCAL, n) + +//--------------------------------------------------------------------+ +// Usage Table +//--------------------------------------------------------------------+ + +/// HID Usage Table - Table 1: Usage Page Summary +enum { + HID_USAGE_PAGE_DESKTOP = 0x01, + HID_USAGE_PAGE_SIMULATE = 0x02, + HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03, + HID_USAGE_PAGE_SPORT = 0x04, + HID_USAGE_PAGE_GAME = 0x05, + HID_USAGE_PAGE_GENERIC_DEVICE = 0x06, + HID_USAGE_PAGE_KEYBOARD = 0x07, + HID_USAGE_PAGE_LED = 0x08, + HID_USAGE_PAGE_BUTTON = 0x09, + HID_USAGE_PAGE_ORDINAL = 0x0a, + HID_USAGE_PAGE_TELEPHONY = 0x0b, + HID_USAGE_PAGE_CONSUMER = 0x0c, + HID_USAGE_PAGE_DIGITIZER = 0x0d, + HID_USAGE_PAGE_PID = 0x0f, + HID_USAGE_PAGE_UNICODE = 0x10, + HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, + HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83 + HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, + HID_USAGE_PAGE_SCALE = 0x8d, + HID_USAGE_PAGE_MSR = 0x8e, + HID_USAGE_PAGE_CAMERA = 0x90, + HID_USAGE_PAGE_ARCADE = 0x91, + HID_USAGE_PAGE_VENDOR = 0xFFFF // 0xFF00 - 0xFFFF +}; + +/// HID Usage Table - Table 6: Generic Desktop Page +enum +{ + HID_USAGE_DESKTOP_POINTER = 0x01, + HID_USAGE_DESKTOP_MOUSE = 0x02, + HID_USAGE_DESKTOP_JOYSTICK = 0x04, + HID_USAGE_DESKTOP_GAMEPAD = 0x05, + HID_USAGE_DESKTOP_KEYBOARD = 0x06, + HID_USAGE_DESKTOP_KEYPAD = 0x07, + HID_USAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 0x08, + HID_USAGE_DESKTOP_TABLET_PC_SYSTEM = 0x09, + HID_USAGE_DESKTOP_X = 0x30, + HID_USAGE_DESKTOP_Y = 0x31, + HID_USAGE_DESKTOP_Z = 0x32, + HID_USAGE_DESKTOP_RX = 0x33, + HID_USAGE_DESKTOP_RY = 0x34, + HID_USAGE_DESKTOP_RZ = 0x35, + HID_USAGE_DESKTOP_SLIDER = 0x36, + HID_USAGE_DESKTOP_DIAL = 0x37, + HID_USAGE_DESKTOP_WHEEL = 0x38, + HID_USAGE_DESKTOP_HAT_SWITCH = 0x39, + HID_USAGE_DESKTOP_COUNTED_BUFFER = 0x3a, + HID_USAGE_DESKTOP_BYTE_COUNT = 0x3b, + HID_USAGE_DESKTOP_MOTION_WAKEUP = 0x3c, + HID_USAGE_DESKTOP_START = 0x3d, + HID_USAGE_DESKTOP_SELECT = 0x3e, + HID_USAGE_DESKTOP_VX = 0x40, + HID_USAGE_DESKTOP_VY = 0x41, + HID_USAGE_DESKTOP_VZ = 0x42, + HID_USAGE_DESKTOP_VBRX = 0x43, + HID_USAGE_DESKTOP_VBRY = 0x44, + HID_USAGE_DESKTOP_VBRZ = 0x45, + HID_USAGE_DESKTOP_VNO = 0x46, + HID_USAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, + HID_USAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, + HID_USAGE_DESKTOP_SYSTEM_CONTROL = 0x80, + HID_USAGE_DESKTOP_SYSTEM_POWER_DOWN = 0x81, + HID_USAGE_DESKTOP_SYSTEM_SLEEP = 0x82, + HID_USAGE_DESKTOP_SYSTEM_WAKE_UP = 0x83, + HID_USAGE_DESKTOP_SYSTEM_CONTEXT_MENU = 0x84, + HID_USAGE_DESKTOP_SYSTEM_MAIN_MENU = 0x85, + HID_USAGE_DESKTOP_SYSTEM_APP_MENU = 0x86, + HID_USAGE_DESKTOP_SYSTEM_MENU_HELP = 0x87, + HID_USAGE_DESKTOP_SYSTEM_MENU_EXIT = 0x88, + HID_USAGE_DESKTOP_SYSTEM_MENU_SELECT = 0x89, + HID_USAGE_DESKTOP_SYSTEM_MENU_RIGHT = 0x8A, + HID_USAGE_DESKTOP_SYSTEM_MENU_LEFT = 0x8B, + HID_USAGE_DESKTOP_SYSTEM_MENU_UP = 0x8C, + HID_USAGE_DESKTOP_SYSTEM_MENU_DOWN = 0x8D, + HID_USAGE_DESKTOP_SYSTEM_COLD_RESTART = 0x8E, + HID_USAGE_DESKTOP_SYSTEM_WARM_RESTART = 0x8F, + HID_USAGE_DESKTOP_DPAD_UP = 0x90, + HID_USAGE_DESKTOP_DPAD_DOWN = 0x91, + HID_USAGE_DESKTOP_DPAD_RIGHT = 0x92, + HID_USAGE_DESKTOP_DPAD_LEFT = 0x93, + HID_USAGE_DESKTOP_SYSTEM_DOCK = 0xA0, + HID_USAGE_DESKTOP_SYSTEM_UNDOCK = 0xA1, + HID_USAGE_DESKTOP_SYSTEM_SETUP = 0xA2, + HID_USAGE_DESKTOP_SYSTEM_BREAK = 0xA3, + HID_USAGE_DESKTOP_SYSTEM_DEBUGGER_BREAK = 0xA4, + HID_USAGE_DESKTOP_APPLICATION_BREAK = 0xA5, + HID_USAGE_DESKTOP_APPLICATION_DEBUGGER_BREAK = 0xA6, + HID_USAGE_DESKTOP_SYSTEM_SPEAKER_MUTE = 0xA7, + HID_USAGE_DESKTOP_SYSTEM_HIBERNATE = 0xA8, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INVERT = 0xB0, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_INTERNAL = 0xB1, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_EXTERNAL = 0xB2, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_BOTH = 0xB3, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_DUAL = 0xB4, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_SWAP_PRIMARY_SECONDARY = 0xB6, + HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 +}; + +/// HID Usage Table: Consumer Page (0x0C) +/// Only contains controls that supported by Windows (whole list is too long) +enum +{ + // Generic Control + HID_USAGE_CONSUMER_CONTROL = 0x0001, + + // Power Control + HID_USAGE_CONSUMER_POWER = 0x0030, + HID_USAGE_CONSUMER_RESET = 0x0031, + HID_USAGE_CONSUMER_SLEEP = 0x0032, + + // Screen Brightness + HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, + HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, + + // These HID usages operate only on mobile systems (battery powered) and + // require Windows 8 (build 8302 or greater). + HID_USAGE_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C, + HID_USAGE_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6, + HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, + HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, + + // Media Control + HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, + HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, + HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, + HID_USAGE_CONSUMER_STOP = 0x00B7, + HID_USAGE_CONSUMER_EJECT = 0x00B8, + + HID_USAGE_CONSUMER_VOLUME = 0x00E0, + HID_USAGE_CONSUMER_MUTE = 0x00E2, + HID_USAGE_CONSUMER_BASS = 0x00E3, + HID_USAGE_CONSUMER_TREBLE = 0x00E4, + HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, + HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, + HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, + HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, + HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, + HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, + HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, + + // Application Launcher + HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, + HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, + HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, + HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, + + // Browser/Explorer Specific + HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, + HID_USAGE_CONSUMER_AC_HOME = 0x0223, + HID_USAGE_CONSUMER_AC_BACK = 0x0224, + HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, + HID_USAGE_CONSUMER_AC_STOP = 0x0226, + HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, + HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, + + // Mouse Horizontal scroll + HID_USAGE_CONSUMER_AC_PAN = 0x0238, +}; + + +#endif /* BLEHIDGENERIC_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp new file mode 100755 index 0000000..cc16f6d --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.cpp @@ -0,0 +1,395 @@ +/**************************************************************************/ +/*! + @file BLEMidi.cpp + @author hathach (tinyusb.org) & toddtreece + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +// GCC 5x new feature to detect optional include +#ifdef __has_include +#if __has_include("MIDI.h") + #include <MIDI.h> + #define MIDI_LIB_INCLUDED +#endif +#endif + + +/* MIDI Service: 03B80E5A-EDE8-4B33-A751-6CE34EC4C700 + * MIDI I/O : 7772E5DB-3868-4112-A1A9-F2669D106BF3 + */ + +const uint8_t BLEMIDI_UUID_SERVICE[] = +{ + 0x00, 0xC7, 0xC4, 0x4E, 0xE3, 0x6C, 0x51, 0xA7, + 0x33, 0x4B, 0xE8, 0xED, 0x5A, 0x0E, 0xB8, 0x03 +}; + +const uint8_t BLEMIDI_UUID_CHR_IO[] = +{ + 0xF3, 0x6B, 0x10, 0x9D, 0x66, 0xF2, 0xA9, 0xA1, + 0x12, 0x41, 0x68, 0x38, 0xDB, 0xE5, 0x72, 0x77 +}; + +/*------------------------------------------------------------------*/ +/* MIDI Data Type + *------------------------------------------------------------------*/ +typedef union ATTR_PACKED +{ + struct { + uint8_t timestamp_hi : 6; + uint8_t : 1; + uint8_t start_bit : 1; + }; + + uint8_t byte; +} midi_header_t; + +VERIFY_STATIC ( sizeof(midi_header_t) == 1 ); + +typedef union ATTR_PACKED +{ + struct { + uint8_t timestamp_low : 7; + uint8_t start_bit : 1; + }; + + uint8_t byte; +} midi_timestamp_t; + +VERIFY_STATIC ( sizeof(midi_timestamp_t) == 1 ); + +typedef struct ATTR_PACKED +{ + midi_header_t header; + midi_timestamp_t timestamp; + uint8_t data[BLE_MIDI_TX_BUFFER_SIZE]; +} midi_event_packet_t; + +VERIFY_STATIC ( sizeof(midi_event_packet_t) == (BLE_MIDI_TX_BUFFER_SIZE + 2) ); + +typedef struct ATTR_PACKED +{ + midi_header_t header; + uint8_t data[BLE_MIDI_TX_BUFFER_SIZE]; +} midi_split_packet_t; + +VERIFY_STATIC ( sizeof(midi_split_packet_t) == (BLE_MIDI_TX_BUFFER_SIZE + 1) ); + +void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset); + +/*------------------------------------------------------------------*/ +/* IMPLEMENTATION + *------------------------------------------------------------------*/ +BLEMidi::BLEMidi(uint16_t fifo_depth) + : BLEService(BLEMIDI_UUID_SERVICE), _io(BLEMIDI_UUID_CHR_IO), _rxd_fifo(1, fifo_depth) +{ + _write_cb = NULL; + _midilib_obj = NULL; +} + +bool BLEMidi::notifyEnabled(void) +{ + return Bluefruit.connPaired() && _io.notifyEnabled(); +} + +void BLEMidi::setWriteCallback(midi_write_cb_t fp) +{ + _write_cb = fp; +} + +void BLEMidi::autoMIDIread(void* midi_obj) +{ + _midilib_obj = midi_obj; +} +void BLEMidi::begin(int baudrate) +{ + (void) baudrate; + begin(); +} + +err_t BLEMidi::begin(void) +{ + _rxd_fifo.begin(); + + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + // IO characteristic + _io.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP | CHR_PROPS_NOTIFY); + _io.setPermission(SECMODE_ENC_NO_MITM, SECMODE_ENC_NO_MITM); + _io.setWriteCallback(blemidi_write_cb); + + VERIFY_STATUS( _io.begin() ); + + // Attempt to change the connection interval to 11.25-15 ms when starting HID + Bluefruit.setConnInterval(9, 12); + + return ERROR_NONE; +} + +/*------------------------------------------------------------------*/ +/* Callbacks + *------------------------------------------------------------------*/ +void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset) +{ + (void) offset; + if ( len < 3 ) return; + + BLEMidi& midi_svc = (BLEMidi&) chr.parentService(); + midi_svc._write_handler(data, len); +} + +void BLEMidi::_write_handler(uint8_t* data, uint16_t len) +{ + // drop the BLE MIDI header byte + data++; + len--; + + while (len) + { + + // timestamp low byte followed by a MIDI status, + // so we drop the timestamp low byte + if ( isStatusByte(data[0]) && isStatusByte(data[1]) ) + { + data++; + len--; + } + // timestamp low byte on it's own (running status), + // so we drop the timestamp low byte + else if ( isStatusByte(data[0]) && ! isStatusByte(data[1]) ) + { + data++; + len--; + } + + // write the status or MIDI data to the FIFO + _rxd_fifo.write(data++, 1); + len--; + } + + // Call write callback if configured + if ( _write_cb ) _write_cb(); + +#ifdef MIDI_LIB_INCLUDED + // read while possible if configured + if ( _midilib_obj ) + { + while( ((midi::MidiInterface<BLEMidi>*)_midilib_obj)->read() ) { } + } +#endif + +} + +/*------------------------------------------------------------------*/ +/* Stream API + *------------------------------------------------------------------*/ +int BLEMidi::read ( void ) +{ + uint8_t ch; + return _rxd_fifo.read(&ch) ? (int) ch : EOF; +} + + +size_t BLEMidi::write ( uint8_t b ) +{ + // MIDI Library will write event byte by byte. + // We need to buffer the data until we have a full event, + // or until we reach the TX buffer limit. + static uint8_t count = 0; + static uint8_t buf[BLE_MIDI_TX_BUFFER_SIZE] = { 0 }; + + // the current byte is a sysex end status message, + // and we still have an existing buffer. send the + // existing buffer and clear it so we can send + // the sysex end status message with the appropriate + // BLE header and timestamp bytes. + if(b == 0xF7 && count > 0) + { + // send and clear the last of the existing buffer. + // it should contain the final bytes in the sysex payload. + if (isStatusByte(buf[0])) + send(buf, count); + else + sendSplit(buf, count); + + // reset buffer + buf[0] = 0; + count = 0; + } + + // add the current byte to the buffer + buf[count++] = b; + + // send matching 1, 2, or 3 byte messages + // and clear the buffer + if ( (oneByteMessage(buf[0]) && count == 1) || + (twoByteMessage(buf[0]) && count == 2) || + (threeByteMessage(buf[0]) && count == 3) ) + { + send(buf, count); + // reset buffer + buf[0] = 0; + count = 0; + } + + // do we have a full buffer at this point? + if(count == BLE_MIDI_TX_BUFFER_SIZE) + { + // send a full or split message depending + // on the type of the first byte in the buffer + if (isStatusByte(buf[0])) + send(buf, count); + else + sendSplit(buf, count); + + // reset buffer + buf[0] = 0; + count = 0; + } + + return 1; +} + +int BLEMidi::available ( void ) +{ + return _rxd_fifo.count(); +} + +int BLEMidi::peek ( void ) +{ + uint8_t ch; + return _rxd_fifo.peek(&ch) ? (int) ch : EOF; +} + +void BLEMidi::flush ( void ) +{ + _rxd_fifo.clear(); +} + +/*------------------------------------------------------------------*/ +/* Message Type Helpers + *------------------------------------------------------------------*/ +bool BLEMidi::isStatusByte( uint8_t b ) +{ + // if the bit 7 is set, then it's a MIDI status message + if (bitRead(b, 7)) + return true; + else + return false; +} + +bool BLEMidi::oneByteMessage( uint8_t status ) +{ + // system messages + if (status >= 0xF4 && status <= 0xFF) return true; + + // system common + if (status == 0xF1) return true; + + // sysex end + if (status == 0xF7) return true; + + return false; +} + +bool BLEMidi::twoByteMessage( uint8_t status ) +{ + // program change, aftertouch + if (status >= 0xC0 && status <= 0xDF) return true; + + // song select + if (status == 0xF3) return true; + + return false; +} + +bool BLEMidi::threeByteMessage( uint8_t status ) +{ + // note off, note on, aftertouch, control change + if (status >= 0x80 && status <= 0xBF) return true; + + // pitch wheel change + if (status >= 0xE0 && status <= 0xEF) return true; + + // song position pointer + if (status == 0xF2) return true; + + return false; +} + +/*------------------------------------------------------------------*/ +/* Send Event (notify) + *------------------------------------------------------------------*/ +bool BLEMidi::send(uint8_t data[], uint8_t len) +{ + uint32_t tstamp = millis(); + + midi_event_packet_t event = + { + .header = {{ + .timestamp_hi = (uint8_t) ((tstamp & 0x1F80UL) >> 7), + .start_bit = 1 + }}, + + .timestamp = {{ + .timestamp_low = (uint8_t) (tstamp & 0x7FUL), + .start_bit = 1 + }} + }; + + memcpy(event.data, data, len); + + // send data length + 1 byte for header + 1 byte for timestamp + return _io.notify(&event, len + 2); +} + +bool BLEMidi::sendSplit(uint8_t data[], uint8_t len) +{ + uint32_t tstamp = millis(); + + midi_split_packet_t event = + { + .header = {{ + .timestamp_hi = (uint8_t) ((tstamp & 0x1F80UL) >> 7), + .start_bit = 1 + }} + }; + + memcpy(event.data, data, len); + + // send data length + 1 byte for header + // don't include the second timestamp byte + return _io.notify(&event, len + 1); +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h new file mode 100755 index 0000000..dbcb872 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEMidi.h @@ -0,0 +1,99 @@ +/**************************************************************************/ +/*! + @file BLEMidi.h + @author hathach (tinyusb.org) & toddtreece + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEMIDI_H_ +#define BLEMIDI_H_ + +#include "bluefruit_common.h" +#include "utility/adafruit_fifo.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +#define MIDI_CREATE_BLE_INSTANCE(midiService) MIDI_CREATE_INSTANCE(BLEMidi, midiService, MIDI) + +#define BLE_MIDI_DEFAULT_FIFO_DEPTH 128 +#define BLE_MIDI_TX_BUFFER_SIZE 3 + +extern const uint8_t BLEMIDI_UUID_SERVICE[]; +extern const uint8_t BLEMIDI_UUID_CHR_IO[]; + +class BLEMidi: public BLEService, public Stream +{ + public: + typedef void (*midi_write_cb_t) (void); + + BLEMidi(uint16_t fifo_depth = BLE_MIDI_DEFAULT_FIFO_DEPTH); + + virtual err_t begin(void); + void begin(int baudrate); // MidiInterface + bool notifyEnabled(void); + + bool send(uint8_t data[], uint8_t len); + bool sendSplit(uint8_t data[], uint8_t len); + + // message type helpers + bool isStatusByte(uint8_t b); + bool oneByteMessage(uint8_t status); + bool twoByteMessage(uint8_t status); + bool threeByteMessage(uint8_t status); + + void setWriteCallback(midi_write_cb_t fp); + void autoMIDIread(void* midi_obj); + + // Stream API for MIDI Interface + virtual int read ( void ); + virtual size_t write ( uint8_t b ); + virtual int available ( void ); + virtual int peek ( void ); + virtual void flush ( void ); + + using Print::write; // pull in write(str) and write(buf, size) from Print + + private: + BLECharacteristic _io; + + Adafruit_FIFO _rxd_fifo; + midi_write_cb_t _write_cb; + + void* _midilib_obj; + + void _write_handler(uint8_t* data, uint16_t len); + + friend void blemidi_write_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset); +}; + + + +#endif /* BLEMIDI_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp new file mode 100755 index 0000000..050ecc8 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.cpp @@ -0,0 +1,325 @@ +/**************************************************************************/ +/*! + @file BLEUart.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" +#include "utility/TimeoutTimer.h" + +/* UART Serivce: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + * UART RXD : 6E400002-B5A3-F393-E0A9-E50E24DCCA9E + * UART TXD : 6E400003-B5A3-F393-E0A9-E50E24DCCA9E + */ + +const uint8_t BLEUART_UUID_SERVICE[] = +{ + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E +}; + +const uint8_t BLEUART_UUID_CHR_RXD[] = +{ + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E +}; + +const uint8_t BLEUART_UUID_CHR_TXD[] = +{ + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E +}; + +/** + * Constructor + */ +BLEUart::BLEUart(uint16_t fifo_depth) + : BLEService(BLEUART_UUID_SERVICE), _txd(BLEUART_UUID_CHR_TXD), _rxd(BLEUART_UUID_CHR_RXD) +{ + _rx_fifo = NULL; + _rx_cb = NULL; + _rx_fifo_depth = fifo_depth; + + _tx_fifo = NULL; + _tx_buffered = 0; + _buffered_th = NULL; +} + +/** + * Destructor + */ +BLEUart::~BLEUart() +{ + if ( _tx_fifo ) delete _tx_fifo; +} + +/** + * Callback when received new data + * @param chr + * @param data + * @param len + * @param offset + */ +void bleuart_rxd_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset) +{ + (void) offset; + + BLEUart& svc = (BLEUart&) chr.parentService(); + svc._rx_fifo->write(data, len); + +#if CFG_DEBUG >= 2 + LOG_LV2("BLEUART", "RX: "); + PRINT_BUFFER(data, len); +#endif + + // invoke user callback + if ( svc._rx_cb ) svc._rx_cb(); +} + +/** + * Timer callback periodically to send TX packet (if enabled). + * @param timer + */ +void bleuart_txd_buffered_hdlr(TimerHandle_t timer) +{ + BLEUart* svc = (BLEUart*) pvTimerGetTimerID(timer); + + // skip if null (unlikely) + if ( !svc->_tx_fifo ) return; + + // flush tx data + (void) svc->flush_tx_buffered(); +} + +void bleuart_txd_cccd_cb(BLECharacteristic& chr, uint16_t value) +{ + BLEUart& svc = (BLEUart&) chr.parentService(); + + if ( svc._buffered_th == NULL) return; + + // Enable TXD timer if configured + if (value & BLE_GATT_HVX_NOTIFICATION) + { + xTimerStart(svc._buffered_th, 0); // if started --> timer got reset + }else + { + xTimerStop(svc._buffered_th, 0); + } +} + +void BLEUart::setRxCallback( rx_callback_t fp) +{ + _rx_cb = fp; +} + +/** + * Enable packet buffered for TXD + * Note: packet is sent right away if it reach MTU bytes + * @param enable true or false + */ +void BLEUart::bufferTXD(uint8_t enable) +{ + _tx_buffered = enable; + + if ( enable ) + { + // enable cccd callback to start timer when enabled + _txd.setCccdWriteCallback(bleuart_txd_cccd_cb); + + // Create FIFO for TX TODO Larger MTU Size + if ( _tx_fifo == NULL ) + { + _tx_fifo = new Adafruit_FIFO(1); + _tx_fifo->begin( Bluefruit.Gap.getMaxMtuByConnCfg(CONN_CFG_PERIPHERAL) ); + } + }else + { + _txd.setCccdWriteCallback(NULL); + + if ( _tx_fifo ) delete _tx_fifo; + } +} + +err_t BLEUart::begin(void) +{ + _rx_fifo = new Adafruit_FIFO(1); + _rx_fifo->begin(_rx_fifo_depth); + + // Invoke base class begin() + VERIFY_STATUS( BLEService::begin() ); + + uint16_t max_mtu = Bluefruit.Gap.getMaxMtuByConnCfg(CONN_CFG_PERIPHERAL); + + // Add TXD Characteristic + _txd.setProperties(CHR_PROPS_NOTIFY); + // TODO enable encryption when bonding is enabled + _txd.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); + _txd.setMaxLen( max_mtu ); + _txd.setUserDescriptor("TXD"); + VERIFY_STATUS( _txd.begin() ); + + // Add RXD Characteristic + _rxd.setProperties(CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP); + _rxd.setWriteCallback(bleuart_rxd_cb); + + // TODO enable encryption when bonding is enabled + _rxd.setPermission(SECMODE_NO_ACCESS, SECMODE_OPEN); + _rxd.setMaxLen( max_mtu ); + _rxd.setUserDescriptor("RXD"); + VERIFY_STATUS(_rxd.begin()); + + return ERROR_NONE; +} + +bool BLEUart::notifyEnabled(void) +{ + return _txd.notifyEnabled(); +} + +void BLEUart::_disconnect_cb(void) +{ + if (_buffered_th) + { + xTimerDelete(_buffered_th, 0); + _buffered_th = NULL; + + if (_tx_fifo) _tx_fifo->clear(); + } +} + +void BLEUart::_connect_cb (void) +{ + if ( _tx_buffered ) + { + // create TXD timer TODO take connInterval into account + // ((5*ms2tick(Bluefruit.connInterval())) / 4) / 2 + _buffered_th = xTimerCreate(NULL, ms2tick(10), true, this, bleuart_txd_buffered_hdlr); + + // Start the timer + xTimerStart(_buffered_th, 0); + } +} + +/*------------------------------------------------------------------*/ +/* STREAM API + *------------------------------------------------------------------*/ +int BLEUart::read (void) +{ + uint8_t ch; + return read(&ch, 1) ? (int) ch : EOF; +} + +int BLEUart::read (uint8_t * buf, size_t size) +{ + return _rx_fifo->read(buf, size); +} + +size_t BLEUart::write (uint8_t b) +{ + return write(&b, 1); +} + +size_t BLEUart::write (const uint8_t *content, size_t len) +{ + // notify right away if txd buffered is not enabled + if ( !(_tx_buffered && _tx_fifo) ) + { + return _txd.notify(content, len) ? len : 0; + }else + { + // skip if not enabled + if ( !notifyEnabled() ) return 0; + + uint16_t written = _tx_fifo->write(content, len); + + // TODO multiple prph connections + // Not up to GATT MTU, notify will be sent later by TXD timer handler + if ( _tx_fifo->count() < (Bluefruit.Gap.getMTU( Bluefruit.connHandle() ) - 3) ) + { + return len; + } + else + { + // TX fifo has enough data, send notify right away + VERIFY( flush_tx_buffered(), 0); + + // still more data left, send them all + if ( written < len ) + { + VERIFY( _txd.notify(content+written, len-written), written); + } + + return len; + } + } +} + +int BLEUart::available (void) +{ + return _rx_fifo->count(); +} + +int BLEUart::peek (void) +{ + uint8_t ch; + return _rx_fifo->peek(&ch) ? (int) ch : EOF; +} + +void BLEUart::flush (void) +{ + _rx_fifo->clear(); +} + +bool BLEUart::flush_tx_buffered(void) +{ + uint16_t max_hvx = Bluefruit.Gap.getMTU( Bluefruit.connHandle() ) - 3; + uint8_t* ff_data = (uint8_t*) rtos_malloc( max_hvx ); + + if (!ff_data) return false; + + uint16_t len = _tx_fifo->read(ff_data, max_hvx); + bool result = true; + + if ( len ) + { + result = _txd.notify(ff_data, len); + } + + rtos_free(ff_data); + + return result; +} + + + + diff --git a/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h new file mode 100755 index 0000000..d8c589d --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/BLEUart.h @@ -0,0 +1,105 @@ +/**************************************************************************/ +/*! + @file BLEUart.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEUART_H_ +#define BLEUART_H_ + +#include "bluefruit_common.h" +#include "utility/adafruit_fifo.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +#define BLE_UART_DEFAULT_FIFO_DEPTH 256 + +extern const uint8_t BLEUART_UUID_SERVICE[]; +extern const uint8_t BLEUART_UUID_CHR_RXD[]; +extern const uint8_t BLEUART_UUID_CHR_TXD[]; + +class BLEUart : public BLEService, public Stream +{ + public: + typedef void (*rx_callback_t) (void); + + BLEUart(uint16_t fifo_depth = BLE_UART_DEFAULT_FIFO_DEPTH); + virtual ~BLEUart(); + + virtual err_t begin(void); + + bool notifyEnabled (void); + void setRxCallback (rx_callback_t fp); + void bufferTXD (uint8_t enable); + + // Stream API + virtual int read ( void ); + virtual int read ( uint8_t * buf, size_t size ); + int read ( char * buf, size_t size ) { return read( (uint8_t*) buf, size); } + virtual size_t write ( uint8_t b ); + virtual size_t write ( const uint8_t *content, size_t len ); + virtual int available ( void ); + virtual int peek ( void ); + virtual void flush ( void ); + + // pull in write(str) and write(buf, size) from Print + using Print::write; + + protected: + BLECharacteristic _txd; + BLECharacteristic _rxd; + + // RXD + Adafruit_FIFO* _rx_fifo; + uint16_t _rx_fifo_depth; + rx_callback_t _rx_cb; + + // TXD + Adafruit_FIFO* _tx_fifo; + uint8_t _tx_buffered; + TimerHandle_t _buffered_th; + + bool flush_tx_buffered(void); + + // from BLEService + virtual void _disconnect_cb(void); + virtual void _connect_cb(void); + + friend void bleuart_rxd_cb(BLECharacteristic& chr, uint8_t* data, uint16_t len, uint16_t offset); + friend void bleuart_txd_cccd_cb(BLECharacteristic& chr, uint16_t value); + friend void bleuart_txd_buffered_hdlr(TimerHandle_t timer); +}; + + + +#endif /* BLEUART_H_ */ diff --git a/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp new file mode 100755 index 0000000..22b45b3 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.cpp @@ -0,0 +1,180 @@ +/**************************************************************************/ +/*! + @file EddyStone.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "bluefruit.h" + +/*------------------------------------------------------------------*/ +/* EddyStone URL + *------------------------------------------------------------------*/ +char const * const prefix_scheme[] = +{ + [0] = "http://www." , + [1] = "https://www." , + [2] = "http://" , + [3] = "https://" +}; +enum { PREFIX_COUNT = sizeof(prefix_scheme)/sizeof(char*) }; + +char const * const url_expansion[] = +{ + [0 ] = ".com/" , + [1 ] = ".org/" , + [2 ] = ".edu/" , + [3 ] = ".net/" , + [4 ] = ".info/" , + [5 ] = ".biz/" , + [6 ] = ".gov/" , + + [7 ] = ".com" , + [8 ] = ".org" , + [9 ] = ".edu" , + [10] = ".net" , + [11] = ".info" , + [12] = ".biz" , + [13] = ".gov" , +}; + +enum { EXPANNSION_COUNT = sizeof(url_expansion)/sizeof(char*) }; + +EddyStoneUrl::EddyStoneUrl(void) +{ + _rssi = 0; + _url = NULL; +} + +EddyStoneUrl::EddyStoneUrl(int8_t rssiAt0m, const char* url) +{ + _rssi = rssiAt0m; + _url = url; +} + +bool EddyStoneUrl::setUrl(const char* url) +{ + _url = url; +} + +void EddyStoneUrl::setRssi(int8_t rssiAt0m) +{ + _rssi = rssiAt0m; +} + +char const* findExpansion(char const* p_url, uint8_t * p_idx) +{ + for(uint8_t i=0; i<EXPANNSION_COUNT; i++) + { + char const * substr = strstr(p_url, url_expansion[i]); + + if ( substr ) + { + *p_idx = i; + return substr; + } + } + + return NULL; +} + +bool EddyStoneUrl::start(void) +{ + enum { URL_MAXLEN = 17 }; + struct ATTR_PACKED { + uint16_t eddy_uuid; + + uint8_t frame_type; + int8_t rssi; + uint8_t url_scheme; + uint8_t urlencode[URL_MAXLEN]; + }eddy = + { + .eddy_uuid = UUID16_SVC_EDDYSTONE, + .frame_type = EDDYSTONE_TYPE_URL, + .rssi = _rssi, + .url_scheme = 0xff + }; + + const char* url = _url; + + // Detect url scheme + for(uint8_t i=0; i<PREFIX_COUNT; i++) + { + uint8_t prelen = strlen(prefix_scheme[i]); + if ( !memcmp(url, prefix_scheme[i], prelen) ) + { + eddy.url_scheme = i; + url += prelen; + + break; + } + } + VERIFY( eddy.url_scheme < PREFIX_COUNT ); + + // Encode url data + uint8_t len = 0; + + while(*url) + { + uint8_t ex_code; + char const * expansion = findExpansion(url, &ex_code); + + // copy url up to the found expansion, if expansion is found, one more + // byte must be reserved for it + uint8_t cp_num = (expansion) ? (expansion-url) : strlen(url); + if ( cp_num > URL_MAXLEN-(len + (expansion ? 1:0)) ) + { + LOG_LV1("EDDYS", "url is too long"); + return false; + } + + memcpy(eddy.urlencode+len, url, cp_num); + url += cp_num; + len += cp_num; + + // copy expansion code if found + if (expansion) + { + eddy.urlencode[len++] = ex_code; + url += strlen(url_expansion[ex_code]); + } + } + + // Add UUID16 list with EddyStone + VERIFY ( Bluefruit.Advertising.addUuid(UUID16_SVC_EDDYSTONE) ); + + // Add Eddystone Service Data + VERIFY ( Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_SERVICE_DATA, &eddy, len + 5) ); + + return true; +} diff --git a/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h new file mode 100755 index 0000000..4dc4585 --- /dev/null +++ b/arduino/libraries/Bluefruit52Lib/src/services/EddyStone.h @@ -0,0 +1,69 @@ +/**************************************************************************/ +/*! + @file EddyStone.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef EDDYSTONE_H_ +#define EDDYSTONE_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +enum +{ + EDDYSTONE_TYPE_UID = 0x00, + EDDYSTONE_TYPE_URL = 0x10, + EDDYSTONE_TYPE_TLM = 0x20, + EDDYSTONE_TYPE_EID = 0x30, +}; + +class EddyStoneUrl +{ + private: + int8_t _rssi; + const char* _url; + + public: + EddyStoneUrl(void); + EddyStoneUrl(int8_t rssiAt0m, const char* url = NULL); + + bool setUrl(const char* url); + void setRssi(int8_t rssiAt0m); + + bool start(void); +}; + + +#endif /* EDDYSTONE_H_ */ |