initial commit
This commit is contained in:
402
lib/NimBLE-Arduino/src/HIDKeyboardTypes.h
Normal file
402
lib/NimBLE-Arduino/src/HIDKeyboardTypes.h
Normal file
@@ -0,0 +1,402 @@
|
||||
/* Copyright (c) 2015 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Note: this file was pulled from different parts of the USBHID library, in mbed SDK
|
||||
*/
|
||||
|
||||
#ifndef KEYBOARD_DEFS_H
|
||||
#define KEYBOARD_DEFS_H
|
||||
|
||||
#define REPORT_ID_KEYBOARD 1
|
||||
#define REPORT_ID_VOLUME 3
|
||||
|
||||
/* Modifiers */
|
||||
enum MODIFIER_KEY {
|
||||
KEY_CTRL = 1,
|
||||
KEY_SHIFT = 2,
|
||||
KEY_ALT = 4,
|
||||
};
|
||||
|
||||
|
||||
enum MEDIA_KEY {
|
||||
KEY_NEXT_TRACK, /*!< next Track Button */
|
||||
KEY_PREVIOUS_TRACK, /*!< Previous track Button */
|
||||
KEY_STOP, /*!< Stop Button */
|
||||
KEY_PLAY_PAUSE, /*!< Play/Pause Button */
|
||||
KEY_MUTE, /*!< Mute Button */
|
||||
KEY_VOLUME_UP, /*!< Volume Up Button */
|
||||
KEY_VOLUME_DOWN, /*!< Volume Down Button */
|
||||
};
|
||||
|
||||
enum FUNCTION_KEY {
|
||||
KEY_F1 = 128, /* F1 key */
|
||||
KEY_F2, /* F2 key */
|
||||
KEY_F3, /* F3 key */
|
||||
KEY_F4, /* F4 key */
|
||||
KEY_F5, /* F5 key */
|
||||
KEY_F6, /* F6 key */
|
||||
KEY_F7, /* F7 key */
|
||||
KEY_F8, /* F8 key */
|
||||
KEY_F9, /* F9 key */
|
||||
KEY_F10, /* F10 key */
|
||||
KEY_F11, /* F11 key */
|
||||
KEY_F12, /* F12 key */
|
||||
|
||||
KEY_PRINT_SCREEN, /* Print Screen key */
|
||||
KEY_SCROLL_LOCK, /* Scroll lock */
|
||||
KEY_CAPS_LOCK, /* caps lock */
|
||||
KEY_NUM_LOCK, /* num lock */
|
||||
KEY_INSERT, /* Insert key */
|
||||
KEY_HOME, /* Home key */
|
||||
KEY_PAGE_UP, /* Page Up key */
|
||||
KEY_PAGE_DOWN, /* Page Down key */
|
||||
|
||||
RIGHT_ARROW, /* Right arrow */
|
||||
LEFT_ARROW, /* Left arrow */
|
||||
DOWN_ARROW, /* Down arrow */
|
||||
UP_ARROW, /* Up arrow */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char usage;
|
||||
unsigned char modifier;
|
||||
} KEYMAP;
|
||||
|
||||
#ifdef US_KEYBOARD
|
||||
/* US keyboard (as HID standard) */
|
||||
#define KEYMAP_SIZE (152)
|
||||
const KEYMAP keymap[KEYMAP_SIZE] = {
|
||||
{0, 0}, /* NUL */
|
||||
{0, 0}, /* SOH */
|
||||
{0, 0}, /* STX */
|
||||
{0, 0}, /* ETX */
|
||||
{0, 0}, /* EOT */
|
||||
{0, 0}, /* ENQ */
|
||||
{0, 0}, /* ACK */
|
||||
{0, 0}, /* BEL */
|
||||
{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
|
||||
{0x2b, 0}, /* TAB */ /* Keyboard Tab */
|
||||
{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
|
||||
{0, 0}, /* VT */
|
||||
{0, 0}, /* FF */
|
||||
{0, 0}, /* CR */
|
||||
{0, 0}, /* SO */
|
||||
{0, 0}, /* SI */
|
||||
{0, 0}, /* DEL */
|
||||
{0, 0}, /* DC1 */
|
||||
{0, 0}, /* DC2 */
|
||||
{0, 0}, /* DC3 */
|
||||
{0, 0}, /* DC4 */
|
||||
{0, 0}, /* NAK */
|
||||
{0, 0}, /* SYN */
|
||||
{0, 0}, /* ETB */
|
||||
{0, 0}, /* CAN */
|
||||
{0, 0}, /* EM */
|
||||
{0, 0}, /* SUB */
|
||||
{0, 0}, /* ESC */
|
||||
{0, 0}, /* FS */
|
||||
{0, 0}, /* GS */
|
||||
{0, 0}, /* RS */
|
||||
{0, 0}, /* US */
|
||||
{0x2c, 0}, /* */
|
||||
{0x1e, KEY_SHIFT}, /* ! */
|
||||
{0x34, KEY_SHIFT}, /* " */
|
||||
{0x20, KEY_SHIFT}, /* # */
|
||||
{0x21, KEY_SHIFT}, /* $ */
|
||||
{0x22, KEY_SHIFT}, /* % */
|
||||
{0x24, KEY_SHIFT}, /* & */
|
||||
{0x34, 0}, /* ' */
|
||||
{0x26, KEY_SHIFT}, /* ( */
|
||||
{0x27, KEY_SHIFT}, /* ) */
|
||||
{0x25, KEY_SHIFT}, /* * */
|
||||
{0x2e, KEY_SHIFT}, /* + */
|
||||
{0x36, 0}, /* , */
|
||||
{0x2d, 0}, /* - */
|
||||
{0x37, 0}, /* . */
|
||||
{0x38, 0}, /* / */
|
||||
{0x27, 0}, /* 0 */
|
||||
{0x1e, 0}, /* 1 */
|
||||
{0x1f, 0}, /* 2 */
|
||||
{0x20, 0}, /* 3 */
|
||||
{0x21, 0}, /* 4 */
|
||||
{0x22, 0}, /* 5 */
|
||||
{0x23, 0}, /* 6 */
|
||||
{0x24, 0}, /* 7 */
|
||||
{0x25, 0}, /* 8 */
|
||||
{0x26, 0}, /* 9 */
|
||||
{0x33, KEY_SHIFT}, /* : */
|
||||
{0x33, 0}, /* ; */
|
||||
{0x36, KEY_SHIFT}, /* < */
|
||||
{0x2e, 0}, /* = */
|
||||
{0x37, KEY_SHIFT}, /* > */
|
||||
{0x38, KEY_SHIFT}, /* ? */
|
||||
{0x1f, KEY_SHIFT}, /* @ */
|
||||
{0x04, KEY_SHIFT}, /* A */
|
||||
{0x05, KEY_SHIFT}, /* B */
|
||||
{0x06, KEY_SHIFT}, /* C */
|
||||
{0x07, KEY_SHIFT}, /* D */
|
||||
{0x08, KEY_SHIFT}, /* E */
|
||||
{0x09, KEY_SHIFT}, /* F */
|
||||
{0x0a, KEY_SHIFT}, /* G */
|
||||
{0x0b, KEY_SHIFT}, /* H */
|
||||
{0x0c, KEY_SHIFT}, /* I */
|
||||
{0x0d, KEY_SHIFT}, /* J */
|
||||
{0x0e, KEY_SHIFT}, /* K */
|
||||
{0x0f, KEY_SHIFT}, /* L */
|
||||
{0x10, KEY_SHIFT}, /* M */
|
||||
{0x11, KEY_SHIFT}, /* N */
|
||||
{0x12, KEY_SHIFT}, /* O */
|
||||
{0x13, KEY_SHIFT}, /* P */
|
||||
{0x14, KEY_SHIFT}, /* Q */
|
||||
{0x15, KEY_SHIFT}, /* R */
|
||||
{0x16, KEY_SHIFT}, /* S */
|
||||
{0x17, KEY_SHIFT}, /* T */
|
||||
{0x18, KEY_SHIFT}, /* U */
|
||||
{0x19, KEY_SHIFT}, /* V */
|
||||
{0x1a, KEY_SHIFT}, /* W */
|
||||
{0x1b, KEY_SHIFT}, /* X */
|
||||
{0x1c, KEY_SHIFT}, /* Y */
|
||||
{0x1d, KEY_SHIFT}, /* Z */
|
||||
{0x2f, 0}, /* [ */
|
||||
{0x31, 0}, /* \ */
|
||||
{0x30, 0}, /* ] */
|
||||
{0x23, KEY_SHIFT}, /* ^ */
|
||||
{0x2d, KEY_SHIFT}, /* _ */
|
||||
{0x35, 0}, /* ` */
|
||||
{0x04, 0}, /* a */
|
||||
{0x05, 0}, /* b */
|
||||
{0x06, 0}, /* c */
|
||||
{0x07, 0}, /* d */
|
||||
{0x08, 0}, /* e */
|
||||
{0x09, 0}, /* f */
|
||||
{0x0a, 0}, /* g */
|
||||
{0x0b, 0}, /* h */
|
||||
{0x0c, 0}, /* i */
|
||||
{0x0d, 0}, /* j */
|
||||
{0x0e, 0}, /* k */
|
||||
{0x0f, 0}, /* l */
|
||||
{0x10, 0}, /* m */
|
||||
{0x11, 0}, /* n */
|
||||
{0x12, 0}, /* o */
|
||||
{0x13, 0}, /* p */
|
||||
{0x14, 0}, /* q */
|
||||
{0x15, 0}, /* r */
|
||||
{0x16, 0}, /* s */
|
||||
{0x17, 0}, /* t */
|
||||
{0x18, 0}, /* u */
|
||||
{0x19, 0}, /* v */
|
||||
{0x1a, 0}, /* w */
|
||||
{0x1b, 0}, /* x */
|
||||
{0x1c, 0}, /* y */
|
||||
{0x1d, 0}, /* z */
|
||||
{0x2f, KEY_SHIFT}, /* { */
|
||||
{0x31, KEY_SHIFT}, /* | */
|
||||
{0x30, KEY_SHIFT}, /* } */
|
||||
{0x35, KEY_SHIFT}, /* ~ */
|
||||
{0,0}, /* DEL */
|
||||
|
||||
{0x3a, 0}, /* F1 */
|
||||
{0x3b, 0}, /* F2 */
|
||||
{0x3c, 0}, /* F3 */
|
||||
{0x3d, 0}, /* F4 */
|
||||
{0x3e, 0}, /* F5 */
|
||||
{0x3f, 0}, /* F6 */
|
||||
{0x40, 0}, /* F7 */
|
||||
{0x41, 0}, /* F8 */
|
||||
{0x42, 0}, /* F9 */
|
||||
{0x43, 0}, /* F10 */
|
||||
{0x44, 0}, /* F11 */
|
||||
{0x45, 0}, /* F12 */
|
||||
|
||||
{0x46, 0}, /* PRINT_SCREEN */
|
||||
{0x47, 0}, /* SCROLL_LOCK */
|
||||
{0x39, 0}, /* CAPS_LOCK */
|
||||
{0x53, 0}, /* NUM_LOCK */
|
||||
{0x49, 0}, /* INSERT */
|
||||
{0x4a, 0}, /* HOME */
|
||||
{0x4b, 0}, /* PAGE_UP */
|
||||
{0x4e, 0}, /* PAGE_DOWN */
|
||||
|
||||
{0x4f, 0}, /* RIGHT_ARROW */
|
||||
{0x50, 0}, /* LEFT_ARROW */
|
||||
{0x51, 0}, /* DOWN_ARROW */
|
||||
{0x52, 0}, /* UP_ARROW */
|
||||
};
|
||||
|
||||
#else
|
||||
/* UK keyboard */
|
||||
#define KEYMAP_SIZE (152)
|
||||
const KEYMAP keymap[KEYMAP_SIZE] = {
|
||||
{0, 0}, /* NUL */
|
||||
{0, 0}, /* SOH */
|
||||
{0, 0}, /* STX */
|
||||
{0, 0}, /* ETX */
|
||||
{0, 0}, /* EOT */
|
||||
{0, 0}, /* ENQ */
|
||||
{0, 0}, /* ACK */
|
||||
{0, 0}, /* BEL */
|
||||
{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
|
||||
{0x2b, 0}, /* TAB */ /* Keyboard Tab */
|
||||
{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
|
||||
{0, 0}, /* VT */
|
||||
{0, 0}, /* FF */
|
||||
{0, 0}, /* CR */
|
||||
{0, 0}, /* SO */
|
||||
{0, 0}, /* SI */
|
||||
{0, 0}, /* DEL */
|
||||
{0, 0}, /* DC1 */
|
||||
{0, 0}, /* DC2 */
|
||||
{0, 0}, /* DC3 */
|
||||
{0, 0}, /* DC4 */
|
||||
{0, 0}, /* NAK */
|
||||
{0, 0}, /* SYN */
|
||||
{0, 0}, /* ETB */
|
||||
{0, 0}, /* CAN */
|
||||
{0, 0}, /* EM */
|
||||
{0, 0}, /* SUB */
|
||||
{0, 0}, /* ESC */
|
||||
{0, 0}, /* FS */
|
||||
{0, 0}, /* GS */
|
||||
{0, 0}, /* RS */
|
||||
{0, 0}, /* US */
|
||||
{0x2c, 0}, /* */
|
||||
{0x1e, KEY_SHIFT}, /* ! */
|
||||
{0x1f, KEY_SHIFT}, /* " */
|
||||
{0x32, 0}, /* # */
|
||||
{0x21, KEY_SHIFT}, /* $ */
|
||||
{0x22, KEY_SHIFT}, /* % */
|
||||
{0x24, KEY_SHIFT}, /* & */
|
||||
{0x34, 0}, /* ' */
|
||||
{0x26, KEY_SHIFT}, /* ( */
|
||||
{0x27, KEY_SHIFT}, /* ) */
|
||||
{0x25, KEY_SHIFT}, /* * */
|
||||
{0x2e, KEY_SHIFT}, /* + */
|
||||
{0x36, 0}, /* , */
|
||||
{0x2d, 0}, /* - */
|
||||
{0x37, 0}, /* . */
|
||||
{0x38, 0}, /* / */
|
||||
{0x27, 0}, /* 0 */
|
||||
{0x1e, 0}, /* 1 */
|
||||
{0x1f, 0}, /* 2 */
|
||||
{0x20, 0}, /* 3 */
|
||||
{0x21, 0}, /* 4 */
|
||||
{0x22, 0}, /* 5 */
|
||||
{0x23, 0}, /* 6 */
|
||||
{0x24, 0}, /* 7 */
|
||||
{0x25, 0}, /* 8 */
|
||||
{0x26, 0}, /* 9 */
|
||||
{0x33, KEY_SHIFT}, /* : */
|
||||
{0x33, 0}, /* ; */
|
||||
{0x36, KEY_SHIFT}, /* < */
|
||||
{0x2e, 0}, /* = */
|
||||
{0x37, KEY_SHIFT}, /* > */
|
||||
{0x38, KEY_SHIFT}, /* ? */
|
||||
{0x34, KEY_SHIFT}, /* @ */
|
||||
{0x04, KEY_SHIFT}, /* A */
|
||||
{0x05, KEY_SHIFT}, /* B */
|
||||
{0x06, KEY_SHIFT}, /* C */
|
||||
{0x07, KEY_SHIFT}, /* D */
|
||||
{0x08, KEY_SHIFT}, /* E */
|
||||
{0x09, KEY_SHIFT}, /* F */
|
||||
{0x0a, KEY_SHIFT}, /* G */
|
||||
{0x0b, KEY_SHIFT}, /* H */
|
||||
{0x0c, KEY_SHIFT}, /* I */
|
||||
{0x0d, KEY_SHIFT}, /* J */
|
||||
{0x0e, KEY_SHIFT}, /* K */
|
||||
{0x0f, KEY_SHIFT}, /* L */
|
||||
{0x10, KEY_SHIFT}, /* M */
|
||||
{0x11, KEY_SHIFT}, /* N */
|
||||
{0x12, KEY_SHIFT}, /* O */
|
||||
{0x13, KEY_SHIFT}, /* P */
|
||||
{0x14, KEY_SHIFT}, /* Q */
|
||||
{0x15, KEY_SHIFT}, /* R */
|
||||
{0x16, KEY_SHIFT}, /* S */
|
||||
{0x17, KEY_SHIFT}, /* T */
|
||||
{0x18, KEY_SHIFT}, /* U */
|
||||
{0x19, KEY_SHIFT}, /* V */
|
||||
{0x1a, KEY_SHIFT}, /* W */
|
||||
{0x1b, KEY_SHIFT}, /* X */
|
||||
{0x1c, KEY_SHIFT}, /* Y */
|
||||
{0x1d, KEY_SHIFT}, /* Z */
|
||||
{0x2f, 0}, /* [ */
|
||||
{0x64, 0}, /* \ */
|
||||
{0x30, 0}, /* ] */
|
||||
{0x23, KEY_SHIFT}, /* ^ */
|
||||
{0x2d, KEY_SHIFT}, /* _ */
|
||||
{0x35, 0}, /* ` */
|
||||
{0x04, 0}, /* a */
|
||||
{0x05, 0}, /* b */
|
||||
{0x06, 0}, /* c */
|
||||
{0x07, 0}, /* d */
|
||||
{0x08, 0}, /* e */
|
||||
{0x09, 0}, /* f */
|
||||
{0x0a, 0}, /* g */
|
||||
{0x0b, 0}, /* h */
|
||||
{0x0c, 0}, /* i */
|
||||
{0x0d, 0}, /* j */
|
||||
{0x0e, 0}, /* k */
|
||||
{0x0f, 0}, /* l */
|
||||
{0x10, 0}, /* m */
|
||||
{0x11, 0}, /* n */
|
||||
{0x12, 0}, /* o */
|
||||
{0x13, 0}, /* p */
|
||||
{0x14, 0}, /* q */
|
||||
{0x15, 0}, /* r */
|
||||
{0x16, 0}, /* s */
|
||||
{0x17, 0}, /* t */
|
||||
{0x18, 0}, /* u */
|
||||
{0x19, 0}, /* v */
|
||||
{0x1a, 0}, /* w */
|
||||
{0x1b, 0}, /* x */
|
||||
{0x1c, 0}, /* y */
|
||||
{0x1d, 0}, /* z */
|
||||
{0x2f, KEY_SHIFT}, /* { */
|
||||
{0x64, KEY_SHIFT}, /* | */
|
||||
{0x30, KEY_SHIFT}, /* } */
|
||||
{0x32, KEY_SHIFT}, /* ~ */
|
||||
{0,0}, /* DEL */
|
||||
|
||||
{0x3a, 0}, /* F1 */
|
||||
{0x3b, 0}, /* F2 */
|
||||
{0x3c, 0}, /* F3 */
|
||||
{0x3d, 0}, /* F4 */
|
||||
{0x3e, 0}, /* F5 */
|
||||
{0x3f, 0}, /* F6 */
|
||||
{0x40, 0}, /* F7 */
|
||||
{0x41, 0}, /* F8 */
|
||||
{0x42, 0}, /* F9 */
|
||||
{0x43, 0}, /* F10 */
|
||||
{0x44, 0}, /* F11 */
|
||||
{0x45, 0}, /* F12 */
|
||||
|
||||
{0x46, 0}, /* PRINT_SCREEN */
|
||||
{0x47, 0}, /* SCROLL_LOCK */
|
||||
{0x39, 0}, /* CAPS_LOCK */
|
||||
{0x53, 0}, /* NUM_LOCK */
|
||||
{0x49, 0}, /* INSERT */
|
||||
{0x4a, 0}, /* HOME */
|
||||
{0x4b, 0}, /* PAGE_UP */
|
||||
{0x4e, 0}, /* PAGE_DOWN */
|
||||
|
||||
{0x4f, 0}, /* RIGHT_ARROW */
|
||||
{0x50, 0}, /* LEFT_ARROW */
|
||||
{0x51, 0}, /* DOWN_ARROW */
|
||||
{0x52, 0}, /* UP_ARROW */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
91
lib/NimBLE-Arduino/src/HIDTypes.h
Normal file
91
lib/NimBLE-Arduino/src/HIDTypes.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2010-2011 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef USBCLASS_HID_TYPES
|
||||
#define USBCLASS_HID_TYPES
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* */
|
||||
#define HID_VERSION_1_11 (0x0111)
|
||||
|
||||
/* HID Class */
|
||||
#define HID_CLASS (3)
|
||||
#define HID_SUBCLASS_NONE (0)
|
||||
#define HID_PROTOCOL_NONE (0)
|
||||
|
||||
/* Descriptors */
|
||||
#define HID_DESCRIPTOR (33)
|
||||
#define HID_DESCRIPTOR_LENGTH (0x09)
|
||||
#define REPORT_DESCRIPTOR (34)
|
||||
|
||||
/* Class requests */
|
||||
#define GET_REPORT (0x1)
|
||||
#define GET_IDLE (0x2)
|
||||
#define SET_REPORT (0x9)
|
||||
#define SET_IDLE (0xa)
|
||||
|
||||
/* HID Class Report Descriptor */
|
||||
/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
|
||||
/* of data as per HID Class standard */
|
||||
|
||||
/* Main items */
|
||||
#define HIDINPUT(size) (0x80 | size)
|
||||
#define HIDOUTPUT(size) (0x90 | size)
|
||||
#define FEATURE(size) (0xb0 | size)
|
||||
#define COLLECTION(size) (0xa0 | size)
|
||||
#define END_COLLECTION(size) (0xc0 | size)
|
||||
|
||||
/* Global items */
|
||||
#define USAGE_PAGE(size) (0x04 | size)
|
||||
#define LOGICAL_MINIMUM(size) (0x14 | size)
|
||||
#define LOGICAL_MAXIMUM(size) (0x24 | size)
|
||||
#define PHYSICAL_MINIMUM(size) (0x34 | size)
|
||||
#define PHYSICAL_MAXIMUM(size) (0x44 | size)
|
||||
#define UNIT_EXPONENT(size) (0x54 | size)
|
||||
#define UNIT(size) (0x64 | size)
|
||||
#define REPORT_SIZE(size) (0x74 | size) //bits
|
||||
#define REPORT_ID(size) (0x84 | size)
|
||||
#define REPORT_COUNT(size) (0x94 | size) //bytes
|
||||
#define PUSH(size) (0xa4 | size)
|
||||
#define POP(size) (0xb4 | size)
|
||||
|
||||
/* Local items */
|
||||
#define USAGE(size) (0x08 | size)
|
||||
#define USAGE_MINIMUM(size) (0x18 | size)
|
||||
#define USAGE_MAXIMUM(size) (0x28 | size)
|
||||
#define DESIGNATOR_INDEX(size) (0x38 | size)
|
||||
#define DESIGNATOR_MINIMUM(size) (0x48 | size)
|
||||
#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
|
||||
#define STRING_INDEX(size) (0x78 | size)
|
||||
#define STRING_MINIMUM(size) (0x88 | size)
|
||||
#define STRING_MAXIMUM(size) (0x98 | size)
|
||||
#define DELIMITER(size) (0xa8 | size)
|
||||
|
||||
/* HID Report */
|
||||
/* Where report IDs are used the first byte of 'data' will be the */
|
||||
/* report ID and 'length' will include this report ID byte. */
|
||||
|
||||
#define MAX_HID_REPORT_SIZE (64)
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint8_t data[MAX_HID_REPORT_SIZE];
|
||||
} HID_REPORT;
|
||||
|
||||
#endif
|
||||
86
lib/NimBLE-Arduino/src/NimBLE2904.cpp
Normal file
86
lib/NimBLE-Arduino/src/NimBLE2904.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* NimBLE2904.cpp
|
||||
*
|
||||
* Created: on March 13, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLE2904.cpp
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
/*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
|
||||
NimBLE2904::NimBLE2904(NimBLECharacteristic* pCharacterisitic)
|
||||
: NimBLEDescriptor(NimBLEUUID((uint16_t) 0x2904),
|
||||
BLE_GATT_CHR_F_READ,
|
||||
sizeof(BLE2904_Data),
|
||||
pCharacterisitic)
|
||||
{
|
||||
m_data.m_format = 0;
|
||||
m_data.m_exponent = 0;
|
||||
m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers
|
||||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // BLE2904
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the description.
|
||||
*/
|
||||
void NimBLE2904::setDescription(uint16_t description) {
|
||||
m_data.m_description = description;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the exponent.
|
||||
*/
|
||||
void NimBLE2904::setExponent(int8_t exponent) {
|
||||
m_data.m_exponent = exponent;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setExponent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the format.
|
||||
*/
|
||||
void NimBLE2904::setFormat(uint8_t format) {
|
||||
m_data.m_format = format;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setFormat
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the namespace.
|
||||
*/
|
||||
void NimBLE2904::setNamespace(uint8_t namespace_value) {
|
||||
m_data.m_namespace = namespace_value;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setNamespace
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the units for this value. It should be one of the encoded values defined here:
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
* @param [in] unit The type of units of this characteristic as defined by assigned numbers.
|
||||
*/
|
||||
void NimBLE2904::setUnit(uint16_t unit) {
|
||||
m_data.m_unit = unit;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setUnit
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
83
lib/NimBLE-Arduino/src/NimBLE2904.h
Normal file
83
lib/NimBLE-Arduino/src/NimBLE2904.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* NimBLE2904.h
|
||||
*
|
||||
* Created: on March 13, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLE2904.h
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLE2904_H_
|
||||
#define MAIN_NIMBLE2904_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEDescriptor.h"
|
||||
|
||||
struct BLE2904_Data {
|
||||
uint8_t m_format;
|
||||
int8_t m_exponent;
|
||||
uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
uint8_t m_namespace;
|
||||
uint16_t m_description;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Characteristic Presentation Format.
|
||||
*
|
||||
* This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
class NimBLE2904: public NimBLEDescriptor {
|
||||
public:
|
||||
NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr);
|
||||
static const uint8_t FORMAT_BOOLEAN = 1;
|
||||
static const uint8_t FORMAT_UINT2 = 2;
|
||||
static const uint8_t FORMAT_UINT4 = 3;
|
||||
static const uint8_t FORMAT_UINT8 = 4;
|
||||
static const uint8_t FORMAT_UINT12 = 5;
|
||||
static const uint8_t FORMAT_UINT16 = 6;
|
||||
static const uint8_t FORMAT_UINT24 = 7;
|
||||
static const uint8_t FORMAT_UINT32 = 8;
|
||||
static const uint8_t FORMAT_UINT48 = 9;
|
||||
static const uint8_t FORMAT_UINT64 = 10;
|
||||
static const uint8_t FORMAT_UINT128 = 11;
|
||||
static const uint8_t FORMAT_SINT8 = 12;
|
||||
static const uint8_t FORMAT_SINT12 = 13;
|
||||
static const uint8_t FORMAT_SINT16 = 14;
|
||||
static const uint8_t FORMAT_SINT24 = 15;
|
||||
static const uint8_t FORMAT_SINT32 = 16;
|
||||
static const uint8_t FORMAT_SINT48 = 17;
|
||||
static const uint8_t FORMAT_SINT64 = 18;
|
||||
static const uint8_t FORMAT_SINT128 = 19;
|
||||
static const uint8_t FORMAT_FLOAT32 = 20;
|
||||
static const uint8_t FORMAT_FLOAT64 = 21;
|
||||
static const uint8_t FORMAT_SFLOAT16 = 22;
|
||||
static const uint8_t FORMAT_SFLOAT32 = 23;
|
||||
static const uint8_t FORMAT_IEEE20601 = 24;
|
||||
static const uint8_t FORMAT_UTF8 = 25;
|
||||
static const uint8_t FORMAT_UTF16 = 26;
|
||||
static const uint8_t FORMAT_OPAQUE = 27;
|
||||
|
||||
void setDescription(uint16_t);
|
||||
void setExponent(int8_t exponent);
|
||||
void setFormat(uint8_t format);
|
||||
void setNamespace(uint8_t namespace_value);
|
||||
void setUnit(uint16_t unit);
|
||||
|
||||
private:
|
||||
friend class NimBLECharacteristic;
|
||||
BLE2904_Data m_data;
|
||||
}; // BLE2904
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLE2904_H_ */
|
||||
197
lib/NimBLE-Arduino/src/NimBLEAddress.cpp
Normal file
197
lib/NimBLE-Arduino/src/NimBLEAddress.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* NimBLEAddress.cpp
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEAddress.cpp
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAddress";
|
||||
|
||||
/*************************************************
|
||||
* NOTE: NimBLE address bytes are in INVERSE ORDER!
|
||||
* We will accomodate that fact in these methods.
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* @brief Create an address from the native NimBLE representation.
|
||||
* @param [in] address The native NimBLE address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(ble_addr_t address) {
|
||||
memcpy(m_address, address.val, 6);
|
||||
m_addrType = address.type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress() {
|
||||
NimBLEAddress("");
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create an address from a hex string
|
||||
*
|
||||
* A hex string is of the format:
|
||||
* ```
|
||||
* 00:00:00:00:00:00
|
||||
* ```
|
||||
* which is 17 characters in length.
|
||||
*
|
||||
* @param [in] stringAddress The hex string representation of the address.
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(const std::string &stringAddress, uint8_t type) {
|
||||
m_addrType = type;
|
||||
|
||||
if (stringAddress.length() == 0) {
|
||||
memset(m_address, 0, 6);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stringAddress.length() == 6) {
|
||||
std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stringAddress.length() != 17) {
|
||||
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
|
||||
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int data[6];
|
||||
if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) {
|
||||
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
|
||||
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
|
||||
}
|
||||
for(size_t index = 0; index < sizeof m_address; index++) {
|
||||
m_address[index] = data[index];
|
||||
}
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for compatibility with bluedroid esp library using native ESP representation.
|
||||
* @param [in] address A uint8_t[6] or esp_bd_addr_t containing the address.
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(uint8_t address[6], uint8_t type) {
|
||||
std::reverse_copy(address, address + sizeof m_address, m_address);
|
||||
m_addrType = type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for address using a hex value.\n
|
||||
* Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16"
|
||||
* @param [in] address uint64_t containing the address.
|
||||
* @param [in] type The type of the address.
|
||||
*/
|
||||
NimBLEAddress::NimBLEAddress(const uint64_t &address, uint8_t type) {
|
||||
memcpy(m_address, &address, sizeof m_address);
|
||||
m_addrType = type;
|
||||
} // NimBLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Determine if this address equals another.
|
||||
* @param [in] otherAddress The other address to compare against.
|
||||
* @return True if the addresses are equal.
|
||||
*/
|
||||
bool NimBLEAddress::equals(const NimBLEAddress &otherAddress) const {
|
||||
return *this == otherAddress;
|
||||
} // equals
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the native representation of the address.
|
||||
* @return a pointer to the uint8_t[6] array of the address.
|
||||
*/
|
||||
const uint8_t *NimBLEAddress::getNative() const {
|
||||
return m_address;
|
||||
} // getNative
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the address type.
|
||||
* @return The address type.
|
||||
*/
|
||||
uint8_t NimBLEAddress::getType() const {
|
||||
return m_addrType;
|
||||
} // getType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a BLE address to a string.
|
||||
*
|
||||
* A string representation of an address is in the format:
|
||||
*
|
||||
* ```
|
||||
* xx:xx:xx:xx:xx:xx
|
||||
* ```
|
||||
*
|
||||
* @return The string representation of the address.
|
||||
* @deprecated Use std::string() operator instead.
|
||||
*/
|
||||
std::string NimBLEAddress::toString() const {
|
||||
return std::string(*this);
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to check if this address is equal to another.
|
||||
*/
|
||||
bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
|
||||
return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
|
||||
} // operator ==
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to check if this address is not equal to another.
|
||||
*/
|
||||
bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const {
|
||||
return !this->operator==(rhs);
|
||||
} // operator !=
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to convert this address to string representation.
|
||||
* @details This allows passing NimBLEAddress to functions
|
||||
* that accept std::string and/or or it's methods as a parameter.
|
||||
*/
|
||||
NimBLEAddress::operator std::string() const {
|
||||
char buffer[18];
|
||||
snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
m_address[5], m_address[4], m_address[3],
|
||||
m_address[2], m_address[1], m_address[0]);
|
||||
return std::string(buffer);
|
||||
} // operator std::string
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to convert the native address representation to uint_64.
|
||||
*/
|
||||
NimBLEAddress::operator uint64_t() const {
|
||||
uint64_t address = 0;
|
||||
memcpy(&address, m_address, sizeof m_address);
|
||||
return address;
|
||||
} // operator uint64_t
|
||||
|
||||
#endif
|
||||
62
lib/NimBLE-Arduino/src/NimBLEAddress.h
Normal file
62
lib/NimBLE-Arduino/src/NimBLEAddress.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* NimBLEAddress.h
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEAddress.h
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEADDRESS_H_
|
||||
#define COMPONENTS_NIMBLEADDRESS_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "nimble/ble.h"
|
||||
#else
|
||||
#include "nimble/nimble/include/nimble/ble.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief A %BLE device address.
|
||||
*
|
||||
* Every %BLE device has a unique address which can be used to identify it and form connections.
|
||||
*/
|
||||
class NimBLEAddress {
|
||||
public:
|
||||
NimBLEAddress();
|
||||
NimBLEAddress(ble_addr_t address);
|
||||
NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC);
|
||||
NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
|
||||
NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC);
|
||||
bool equals(const NimBLEAddress &otherAddress) const;
|
||||
const uint8_t* getNative() const;
|
||||
std::string toString() const;
|
||||
uint8_t getType() const;
|
||||
|
||||
bool operator ==(const NimBLEAddress & rhs) const;
|
||||
bool operator !=(const NimBLEAddress & rhs) const;
|
||||
operator std::string() const;
|
||||
operator uint64_t() const;
|
||||
|
||||
private:
|
||||
uint8_t m_address[6];
|
||||
uint8_t m_addrType;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_NIMBLEADDRESS_H_ */
|
||||
785
lib/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp
Normal file
785
lib/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp
Normal file
@@ -0,0 +1,785 @@
|
||||
/*
|
||||
* NimBLEAdvertisedDevice.cpp
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEAdvertisedDevice.cpp
|
||||
*
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
static const char* LOG_TAG = "NimBLEAdvertisedDevice";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() :
|
||||
m_payload(62,0)
|
||||
{
|
||||
m_advType = 0;
|
||||
m_rssi = -9999;
|
||||
m_callbackSent = false;
|
||||
m_timestamp = 0;
|
||||
m_advLength = 0;
|
||||
} // NimBLEAdvertisedDevice
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the address of the advertising device.
|
||||
* @return The address of the advertised device.
|
||||
*/
|
||||
NimBLEAddress NimBLEAdvertisedDevice::getAddress() {
|
||||
return m_address;
|
||||
} // getAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertisement type.
|
||||
* @return The advertising type the device is reporting:
|
||||
* * BLE_HCI_ADV_TYPE_ADV_IND (0) - indirect advertising
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD (1) - direct advertisng - high duty cycle
|
||||
* * BLE_HCI_ADV_TYPE_ADV_SCAN_IND (2) - indirect scan response
|
||||
* * BLE_HCI_ADV_TYPE_ADV_NONCONN_IND (3) - indirect advertisng - not connectable
|
||||
* * BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD (4) - direct advertising - low duty cycle
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvType() {
|
||||
return m_advType;
|
||||
} // getAdvType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the appearance.
|
||||
*
|
||||
* A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user
|
||||
* typcially in the form of an icon.
|
||||
*
|
||||
* @return The appearance of the advertised device.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAppearance() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertisement interval.
|
||||
* @return The advertisement interval in 0.625ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getAdvInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the preferred min connection interval.
|
||||
* @return The preferred min connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMinInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
|
||||
return *field->value | *(field->value + 1) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getMinInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the preferred max connection interval.
|
||||
* @return The preferred max connection interval in 1.25ms units.
|
||||
*/
|
||||
uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
|
||||
return *(field->value + 2) | *(field->value + 3) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // getMaxInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the manufacturer data.
|
||||
* @return The manufacturer data of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getManufacturerData() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the URI from the advertisement.
|
||||
* @return The URI data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getURI() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getURI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertised name.
|
||||
* @return The name of the advertised device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getName() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0)
|
||||
{
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > 1) {
|
||||
return std::string((char*)field->value, field->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} // getName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the RSSI.
|
||||
* @return The RSSI of the advertised device.
|
||||
*/
|
||||
int NimBLEAdvertisedDevice::getRSSI() {
|
||||
return m_rssi;
|
||||
} // getRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the scan object that created this advertised device.
|
||||
* @return The scan object.
|
||||
*/
|
||||
NimBLEScan* NimBLEAdvertisedDevice::getScan() {
|
||||
return NimBLEDevice::getScan();
|
||||
} // getScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of target addresses.
|
||||
* @return The number of addresses.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the target address at the index.
|
||||
* @param [in] index The index of the target address.
|
||||
* @return The target address.
|
||||
*/
|
||||
NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t count = 0;
|
||||
uint8_t data_loc = 0xFF;
|
||||
|
||||
index++;
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
|
||||
|
||||
if (count < index) {
|
||||
index -= count;
|
||||
count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
|
||||
}
|
||||
|
||||
if(count > 0 && data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||
index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
|
||||
}
|
||||
if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
|
||||
return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
return NimBLEAddress("");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @param [in] index The index of the service data requested.
|
||||
* @return The advertised service data or empty string if no data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length > bytes) {
|
||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
} //getServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @param [in] uuid The uuid of the service data requested.
|
||||
* @return The advertised service data or empty string if no data.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t index = 0;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
uint8_t uuidBytes = uuid.bitSize() / 8;
|
||||
uint8_t plSize = m_payload.size() - 2;
|
||||
|
||||
while(data_loc < plSize) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) {
|
||||
return std::string((char*)(field->value + bytes), field->length - bytes - 1);
|
||||
}
|
||||
|
||||
index++;
|
||||
data_loc = findServiceData(index, &bytes);
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "No service data found");
|
||||
return "";
|
||||
} //getServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the serice data at the index.
|
||||
* @param [in] index The index of the service data UUID requested.
|
||||
* @return The advertised service data UUID or an empty UUID if not found.
|
||||
*/
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t bytes;
|
||||
uint8_t data_loc = findServiceData(index, &bytes);
|
||||
|
||||
if(data_loc != 0xFF) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length >= bytes) {
|
||||
return NimBLEUUID(field->value, bytes, false);
|
||||
}
|
||||
}
|
||||
|
||||
return NimBLEUUID("");
|
||||
} // getServiceDataUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Find the service data at the index.
|
||||
* @param [in] index The index of the service data to find.
|
||||
* @param [in] bytes A pointer to storage for the number of the bytes in the UUID.
|
||||
* @return The index in the vector where the data is located, 0xFF if not found.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t found = 0;
|
||||
|
||||
*bytes = 0;
|
||||
index++;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 2;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
index -= found;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 4;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
index -= found;
|
||||
found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc);
|
||||
if(found == index) {
|
||||
*bytes = 16;
|
||||
return data_loc;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the count of advertised service data UUIDS
|
||||
* @return The number of service data UUIDS in the vector.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getServiceDataCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128);
|
||||
|
||||
return count;
|
||||
} // getServiceDataCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @param [in] index The index of the service UUID requested.
|
||||
* @return The Service UUID of the advertised service, or an empty UUID if not found.
|
||||
*/
|
||||
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
|
||||
uint8_t count = 0;
|
||||
uint8_t data_loc = 0;
|
||||
uint8_t uuidBytes = 0;
|
||||
uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
|
||||
index++;
|
||||
|
||||
do {
|
||||
count = findAdvField(type, index, &data_loc);
|
||||
if(count >= index) {
|
||||
if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) {
|
||||
uuidBytes = 2;
|
||||
} else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) {
|
||||
uuidBytes = 4;
|
||||
} else {
|
||||
uuidBytes = 16;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
type++;
|
||||
index -= count;
|
||||
}
|
||||
|
||||
} while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128);
|
||||
|
||||
if(uuidBytes > 0) {
|
||||
field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
// In the case of more than one field of service uuid's we need to adjust
|
||||
// the index to account for the uuids of the previous fields.
|
||||
if(field->length < index * uuidBytes) {
|
||||
index -= count - field->length / uuidBytes;
|
||||
}
|
||||
|
||||
if(field->length > uuidBytes * index) {
|
||||
return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false);
|
||||
}
|
||||
}
|
||||
|
||||
return NimBLEUUID("");
|
||||
} // getServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of services advertised
|
||||
* @return The count of services in the advertising packet.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
uint8_t count = 0;
|
||||
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
|
||||
count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128);
|
||||
|
||||
return count;
|
||||
} // getServiceUUIDCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check advertised services for existance of the required UUID
|
||||
* @param [in] uuid The service uuid to look for in the advertisement.
|
||||
* @return Return true if service is advertised
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) {
|
||||
size_t count = getServiceUUIDCount();
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
if(uuid == getServiceUUID(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} // isAdvertisingService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the TX Power.
|
||||
* @return The TX Power of the advertised device.
|
||||
*/
|
||||
int8_t NimBLEAdvertisedDevice::getTXPower() {
|
||||
uint8_t data_loc = 0;
|
||||
|
||||
if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) {
|
||||
ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
|
||||
if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) {
|
||||
return *(int8_t*)field->value;
|
||||
}
|
||||
}
|
||||
|
||||
return -99;
|
||||
} // getTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have preferred connection parameters?
|
||||
* @return True if connection parameters are present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveConnParams() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0;
|
||||
} // haveConnParams
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have have the advertising interval?
|
||||
* @return True if the advertisement interval is present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveAdvInterval() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0;
|
||||
} // haveAdvInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have an appearance value?
|
||||
* @return True if there is an appearance value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveAppearance() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0;
|
||||
} // haveAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have manufacturer data?
|
||||
* @return True if there is manufacturer data present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveManufacturerData() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0;
|
||||
} // haveManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a URI?
|
||||
* @return True if there is a URI present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveURI() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_URI) > 0;
|
||||
} // haveURI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the advertisement contain a target address?
|
||||
* @return True if an address is present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveTargetAddress() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a name value?
|
||||
* @return True if there is a name value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveName() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 ||
|
||||
findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0;
|
||||
} // haveName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a signal strength value?
|
||||
* @return True if there is a signal strength value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveRSSI() {
|
||||
return m_rssi != -9999;
|
||||
} // haveRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a service data value?
|
||||
* @return True if there is a service data value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveServiceData() {
|
||||
return getServiceDataCount() > 0;
|
||||
} // haveServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a service UUID value?
|
||||
* @return True if there is a service UUID value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveServiceUUID() {
|
||||
return getServiceUUIDCount() > 0;
|
||||
} // haveServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a transmission power value?
|
||||
* @return True if there is a transmission power value present.
|
||||
*/
|
||||
bool NimBLEAdvertisedDevice::haveTXPower() {
|
||||
return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0;
|
||||
} // haveTXPower
|
||||
|
||||
|
||||
uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) {
|
||||
ble_hs_adv_field *field = nullptr;
|
||||
uint8_t data = 0;
|
||||
uint8_t length = m_payload.size();
|
||||
uint8_t count = 0;
|
||||
|
||||
if(length < 2) {
|
||||
return count;
|
||||
}
|
||||
|
||||
while (length > 1) {
|
||||
field = (ble_hs_adv_field*)&m_payload[data];
|
||||
|
||||
if (field->length >= length) {
|
||||
return count;
|
||||
}
|
||||
|
||||
if (field->type == type) {
|
||||
switch(type) {
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS16:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS16:
|
||||
count += field->length / 2;
|
||||
break;
|
||||
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS32:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS32:
|
||||
count += field->length / 4;
|
||||
break;
|
||||
|
||||
case BLE_HS_ADV_TYPE_INCOMP_UUIDS128:
|
||||
case BLE_HS_ADV_TYPE_COMP_UUIDS128:
|
||||
count += field->length / 16;
|
||||
break;
|
||||
|
||||
case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR:
|
||||
case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR:
|
||||
count += field->length / 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(data_loc != nullptr) {
|
||||
if(index == 0 || count >= index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
length -= 1 + field->length;
|
||||
data += 1 + field->length;
|
||||
}
|
||||
|
||||
if(data_loc != nullptr && field != nullptr) {
|
||||
*data_loc = data;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the address of the advertised device.
|
||||
* @param [in] address The address of the advertised device.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
|
||||
m_address = address;
|
||||
} // setAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the adFlag for this device.
|
||||
* @param [in] advType The advertisement flag data from the advertisement.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
|
||||
m_advType = advType;
|
||||
} // setAdvType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the RSSI for this device.
|
||||
* @param [in] rssi The RSSI of the discovered device.
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setRSSI(int rssi) {
|
||||
m_rssi = rssi;
|
||||
} // setRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this device.
|
||||
* @return A string representation of this device.
|
||||
*/
|
||||
std::string NimBLEAdvertisedDevice::toString() {
|
||||
std::string res = "Name: " + getName() + ", Address: " + getAddress().toString();
|
||||
|
||||
if (haveAppearance()) {
|
||||
char val[6];
|
||||
snprintf(val, sizeof(val), "%d", getAppearance());
|
||||
res += ", appearance: ";
|
||||
res += val;
|
||||
}
|
||||
|
||||
if (haveManufacturerData()) {
|
||||
char *pHex = NimBLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length());
|
||||
res += ", manufacturer data: ";
|
||||
res += pHex;
|
||||
free(pHex);
|
||||
}
|
||||
|
||||
if (haveServiceUUID()) {
|
||||
res += ", serviceUUID: " + getServiceUUID().toString();
|
||||
}
|
||||
|
||||
if (haveTXPower()) {
|
||||
char val[5];
|
||||
snprintf(val, sizeof(val), "%d", getTXPower());
|
||||
res += ", txPower: ";
|
||||
res += val;
|
||||
}
|
||||
|
||||
if(haveServiceData()) {
|
||||
size_t count = getServiceDataCount();
|
||||
res += "\nService Data:";
|
||||
for(size_t i = 0; i < count; i++) {
|
||||
res += "\nUUID: " + std::string(getServiceDataUUID(i));
|
||||
res += ", Data: " + getServiceData(i);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the payload advertised by the device.
|
||||
* @return The advertisement payload.
|
||||
*/
|
||||
uint8_t* NimBLEAdvertisedDevice::getPayload() {
|
||||
return &m_payload[0];
|
||||
} // getPayload
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stores the payload of the advertised device in a vector.
|
||||
* @param [in] payload The advertisement payload.
|
||||
* @param [in] length The length of the payload in bytes.
|
||||
* @param [in] append Indicates if the the data should be appended (scan response).
|
||||
*/
|
||||
void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length, bool append) {
|
||||
if(!append) {
|
||||
m_advLength = length;
|
||||
m_payload.assign(payload, payload + length);
|
||||
} else {
|
||||
m_payload.insert(m_payload.end(), payload, payload + length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the advertisement data in the payload.
|
||||
* @return The number of bytes in the payload that is from the advertisment.
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAdvLength() {
|
||||
return m_advLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertised device address type.
|
||||
* @return The device address type:
|
||||
* * BLE_ADDR_PUBLIC (0x00)
|
||||
* * BLE_ADDR_RANDOM (0x01)
|
||||
* * BLE_ADDR_PUBLIC_ID (0x02)
|
||||
* * BLE_ADDR_RANDOM_ID (0x03)
|
||||
*/
|
||||
uint8_t NimBLEAdvertisedDevice::getAddressType() {
|
||||
return m_address.getType();
|
||||
} // getAddressType
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the timeStamp of when the device last advertised.
|
||||
* @return The timeStamp of when the device was last seen.
|
||||
*/
|
||||
time_t NimBLEAdvertisedDevice::getTimestamp() {
|
||||
return m_timestamp;
|
||||
} // getTimestamp
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the payload advertised by the device.
|
||||
* @return The size of the payload in bytes.
|
||||
*/
|
||||
size_t NimBLEAdvertisedDevice::getPayloadLength() {
|
||||
return m_payload.size();
|
||||
} // getPayloadLength
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
|
||||
177
lib/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h
Normal file
177
lib/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* NimBLEAdvertisedDevice.h
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEAdvertisedDevice.h
|
||||
*
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#define COMPONENTS_NIMBLEADVERTISEDDEVICE_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEScan.h"
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_hs_adv.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_hs_adv.h"
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
class NimBLEScan;
|
||||
/**
|
||||
* @brief A representation of a %BLE advertised device found by a scan.
|
||||
*
|
||||
* When we perform a %BLE scan, the result will be a set of devices that are advertising. This
|
||||
* class provides a model of a detected device.
|
||||
*/
|
||||
class NimBLEAdvertisedDevice {
|
||||
public:
|
||||
NimBLEAdvertisedDevice();
|
||||
|
||||
NimBLEAddress getAddress();
|
||||
uint8_t getAdvType();
|
||||
uint16_t getAppearance();
|
||||
uint16_t getAdvInterval();
|
||||
uint16_t getMinInterval();
|
||||
uint16_t getMaxInterval();
|
||||
std::string getManufacturerData();
|
||||
std::string getURI();
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getManufacturerData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getManufacturerData(bool skipSizeCheck = false) {
|
||||
std::string data = getManufacturerData();
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
std::string getName();
|
||||
int getRSSI();
|
||||
NimBLEScan* getScan();
|
||||
size_t getServiceDataCount();
|
||||
std::string getServiceData(uint8_t index = 0);
|
||||
std::string getServiceData(const NimBLEUUID &uuid);
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <tt><type\></tt>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] index The vector index of the service data requested.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getServiceData(uint8_t index = 0, bool skipSizeCheck = false) {
|
||||
std::string data = getServiceData(index);
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A template to convert the service data to <tt><type\></tt>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] uuid The uuid of the service data requested.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getServiceData<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getServiceData(const NimBLEUUID &uuid, bool skipSizeCheck = false) {
|
||||
std::string data = getServiceData(uuid);
|
||||
if(!skipSizeCheck && data.size() < sizeof(T)) return T();
|
||||
const char *pData = data.data();
|
||||
return *((T *)pData);
|
||||
}
|
||||
|
||||
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
|
||||
NimBLEUUID getServiceUUID(uint8_t index = 0);
|
||||
size_t getServiceUUIDCount();
|
||||
NimBLEAddress getTargetAddress(uint8_t index = 0);
|
||||
size_t getTargetAddressCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
uint8_t getAdvLength();
|
||||
size_t getPayloadLength();
|
||||
uint8_t getAddressType();
|
||||
time_t getTimestamp();
|
||||
bool isAdvertisingService(const NimBLEUUID &uuid);
|
||||
bool haveAppearance();
|
||||
bool haveManufacturerData();
|
||||
bool haveName();
|
||||
bool haveRSSI();
|
||||
bool haveServiceData();
|
||||
bool haveServiceUUID();
|
||||
bool haveTXPower();
|
||||
bool haveConnParams();
|
||||
bool haveAdvInterval();
|
||||
bool haveTargetAddress();
|
||||
bool haveURI();
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
friend class NimBLEScan;
|
||||
|
||||
void setAddress(NimBLEAddress address);
|
||||
void setAdvType(uint8_t advType);
|
||||
void setPayload(const uint8_t *payload, uint8_t length, bool append);
|
||||
void setRSSI(int rssi);
|
||||
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
|
||||
uint8_t findServiceData(uint8_t index, uint8_t* bytes);
|
||||
|
||||
NimBLEAddress m_address = NimBLEAddress("");
|
||||
uint8_t m_advType;
|
||||
int m_rssi;
|
||||
time_t m_timestamp;
|
||||
bool m_callbackSent;
|
||||
uint8_t m_advLength;
|
||||
|
||||
std::vector<uint8_t> m_payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A callback handler for callbacks associated device scanning.
|
||||
*
|
||||
* When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising
|
||||
* has been found. This class can be sub-classed and registered such that when a scan is performed and
|
||||
* a new advertised device has been found, we will be called back to be notified.
|
||||
*/
|
||||
class NimBLEAdvertisedDeviceCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEAdvertisedDeviceCallbacks() {}
|
||||
/**
|
||||
* @brief Called when a new scan result is detected.
|
||||
*
|
||||
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
|
||||
* device that was found. During any individual scan, a device will only be detected one time.
|
||||
*/
|
||||
virtual void onResult(NimBLEAdvertisedDevice* advertisedDevice) = 0;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* COMPONENTS_NIMBLEADVERTISEDDEVICE_H_ */
|
||||
1029
lib/NimBLE-Arduino/src/NimBLEAdvertising.cpp
Normal file
1029
lib/NimBLE-Arduino/src/NimBLEAdvertising.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
lib/NimBLE-Arduino/src/NimBLEAdvertising.h
Normal file
138
lib/NimBLE-Arduino/src/NimBLEAdvertising.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* NimBLEAdvertising.h
|
||||
*
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEAdvertising.h
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_BLEADVERTISING_H_
|
||||
#define MAIN_BLEADVERTISING_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/* COMPATIBILITY - DO NOT USE */
|
||||
#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0)
|
||||
#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1)
|
||||
#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2)
|
||||
#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3)
|
||||
#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4)
|
||||
#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 )
|
||||
/* ************************* */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
||||
*/
|
||||
class NimBLEAdvertisementData {
|
||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||
// be exposed on demand/request or as time permits.
|
||||
//
|
||||
public:
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(const NimBLEUUID &uuid);
|
||||
void setCompleteServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setCompleteServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setFlags(uint8_t);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setName(const std::string &name);
|
||||
void setPartialServices(const NimBLEUUID &uuid);
|
||||
void setPartialServices16(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setPartialServices32(const std::vector<NimBLEUUID> &v_uuid);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setShortName(const std::string &name);
|
||||
void addData(const std::string &data); // Add data to the payload.
|
||||
void addData(char * data, size_t length);
|
||||
void addTxPower();
|
||||
void setPreferredParams(uint16_t min, uint16_t max);
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
friend class NimBLEAdvertising;
|
||||
void setServices(const bool complete, const uint8_t size,
|
||||
const std::vector<NimBLEUUID> &v_uuid);
|
||||
std::string m_payload; // The payload of the advertisement.
|
||||
}; // NimBLEAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE advertising.
|
||||
*
|
||||
* A %BLE server will want to perform advertising in order to make itself known to %BLE clients.
|
||||
*/
|
||||
class NimBLEAdvertising {
|
||||
public:
|
||||
NimBLEAdvertising();
|
||||
void addServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void removeServiceUUID(const NimBLEUUID &serviceUUID);
|
||||
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setName(const std::string &name);
|
||||
void setManufacturerData(const std::string &data);
|
||||
void setURI(const std::string &uri);
|
||||
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
|
||||
void setAdvertisementType(uint8_t adv_type);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(NimBLEAdvertisementData& advertisementData);
|
||||
void setScanResponse(bool);
|
||||
void setMinPreferred(uint16_t);
|
||||
void setMaxPreferred(uint16_t);
|
||||
void addTxPower();
|
||||
void reset();
|
||||
void advCompleteCB();
|
||||
bool isAdvertising();
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
|
||||
void onHostSync();
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
|
||||
ble_hs_adv_fields m_advData;
|
||||
ble_hs_adv_fields m_scanData;
|
||||
ble_gap_adv_params m_advParams;
|
||||
std::vector<NimBLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData;
|
||||
bool m_customScanResponseData;
|
||||
bool m_scanResp;
|
||||
bool m_advDataSet;
|
||||
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
|
||||
uint8_t m_slaveItvl[4];
|
||||
uint32_t m_duration;
|
||||
std::vector<uint8_t> m_svcData16;
|
||||
std::vector<uint8_t> m_svcData32;
|
||||
std::vector<uint8_t> m_svcData128;
|
||||
std::vector<uint8_t> m_name;
|
||||
std::vector<uint8_t> m_mfgData;
|
||||
std::vector<uint8_t> m_uri;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
#endif /* MAIN_BLEADVERTISING_H_ */
|
||||
447
lib/NimBLE-Arduino/src/NimBLEAttValue.h
Normal file
447
lib/NimBLE-Arduino/src/NimBLEAttValue.h
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* NimBLEAttValue.h
|
||||
*
|
||||
* Created: on March 18, 2021
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLEATTVALUE_H_
|
||||
#define MAIN_NIMBLEATTVALUE_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include "NimBLELog.h"
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
|
||||
# define CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH 20
|
||||
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH > BLE_ATT_ATTR_MAX_LEN
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be larger than 512 (BLE_ATT_ATTR_MAX_LEN)
|
||||
#elif CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH < 1
|
||||
# error CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH cannot be less than 1; Range = 1 : 512
|
||||
#endif
|
||||
|
||||
|
||||
/* Used to determine if the type passed to a template has a c_str() and length() method. */
|
||||
template <typename T, typename = void, typename = void>
|
||||
struct Has_c_str_len : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct Has_c_str_len<T, decltype(void(std::declval<T &>().c_str())),
|
||||
decltype(void(std::declval<T &>().length()))> : std::true_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A specialized container class to hold BLE attribute values.
|
||||
* @details This class is designed to be more memory efficient than using\n
|
||||
* standard container types for value storage, while being convertable to\n
|
||||
* many different container classes.
|
||||
*/
|
||||
class NimBLEAttValue
|
||||
{
|
||||
uint8_t* m_attr_value = nullptr;
|
||||
uint16_t m_attr_max_len = 0;
|
||||
uint16_t m_attr_len = 0;
|
||||
uint16_t m_capacity = 0;
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t m_timestamp = 0;
|
||||
#endif
|
||||
void deepCopy(const NimBLEAttValue & source);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
* @param[in] init_len The initial size in bytes.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(uint16_t init_len = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a buffer.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] len The size in bytes of the value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const uint8_t *value, uint16_t len,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
/**
|
||||
* @brief Construct with an initializer list.
|
||||
* @param list An initializer list containing the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(std::initializer_list<uint8_t> list,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue(list.begin(), (uint16_t)list.size(), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a const char string.
|
||||
* @param value A pointer to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const char *value, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)value, (uint16_t)strlen(value), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::string.
|
||||
* @param str A std::string containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::string str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)str.data(), (uint16_t)str.length(), max_len){}
|
||||
|
||||
/**
|
||||
* @brief Construct with an initial value from a std::vector<uint8_t>.
|
||||
* @param vec A std::vector<uint8_t> containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const std::vector<uint8_t> vec, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue(&vec[0], (uint16_t)vec.size(), max_len){}
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/**
|
||||
* @brief Construct with an initial value from an Arduino String.
|
||||
* @param str An Arduino String containing to the initial value to set.
|
||||
* @param[in] max_len The max size in bytes that the value can be.
|
||||
*/
|
||||
NimBLEAttValue(const String str, uint16_t max_len = BLE_ATT_ATTR_MAX_LEN)
|
||||
:NimBLEAttValue((uint8_t*)str.c_str(), str.length(), max_len){}
|
||||
#endif
|
||||
|
||||
/** @brief Copy constructor */
|
||||
NimBLEAttValue(const NimBLEAttValue & source) { deepCopy(source); }
|
||||
|
||||
/** @brief Move constructor */
|
||||
NimBLEAttValue(NimBLEAttValue && source) { *this = std::move(source); }
|
||||
|
||||
/** @brief Destructor */
|
||||
~NimBLEAttValue();
|
||||
|
||||
/** @brief Returns the max size in bytes */
|
||||
uint16_t max_size() const { return m_attr_max_len; }
|
||||
|
||||
/** @brief Returns the currently allocated capacity in bytes */
|
||||
uint16_t capacity() const { return m_capacity; }
|
||||
|
||||
/** @brief Returns the current length of the value in bytes */
|
||||
uint16_t length() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns the current size of the value in bytes */
|
||||
uint16_t size() const { return m_attr_len; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value */
|
||||
const uint8_t* data() const { return m_attr_value; }
|
||||
|
||||
/** @brief Returns a pointer to the internal buffer of the value as a const char* */
|
||||
const char* c_str() const { return (const char*)m_attr_value; }
|
||||
|
||||
/** @brief Iterator begin */
|
||||
const uint8_t* begin() const { return m_attr_value; }
|
||||
|
||||
/** @brief Iterator end */
|
||||
const uint8_t* end() const { return m_attr_value + m_attr_len; }
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
/** @brief Returns a timestamp of when the value was last updated */
|
||||
time_t getTimeStamp() const { return m_timestamp; }
|
||||
|
||||
/** @brief Set the timestamp to the current time */
|
||||
void setTimeStamp() { m_timestamp = time(nullptr); }
|
||||
|
||||
/**
|
||||
* @brief Set the timestamp to the specified time
|
||||
* @param[in] t The timestamp value to set
|
||||
*/
|
||||
void setTimeStamp(time_t t) { m_timestamp = t; }
|
||||
#else
|
||||
time_t getTimeStamp() const { return 0; }
|
||||
void setTimeStamp() { }
|
||||
void setTimeStamp(time_t t) { }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set the value from a buffer
|
||||
* @param[in] value A ponter to a buffer containing the value.
|
||||
* @param[in] len The length of the value in bytes.
|
||||
* @returns True if successful.
|
||||
*/
|
||||
bool setValue(const uint8_t *value, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Set value to the value of const char*.
|
||||
* @param [in] s A ponter to a const char value to set.
|
||||
*/
|
||||
bool setValue(const char* s) {
|
||||
return setValue((uint8_t*)s, (uint16_t)strlen(s)); }
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the value buffer with timestamp.
|
||||
* @param[in] timestamp A ponter to a time_t variable to store the timestamp.
|
||||
* @returns A pointer to the internal value buffer.
|
||||
*/
|
||||
const uint8_t* getValue(time_t *timestamp);
|
||||
|
||||
/**
|
||||
* @brief Append data to the value.
|
||||
* @param[in] value A ponter to a data buffer with the value to append.
|
||||
* @param[in] len The length of the value to append in bytes.
|
||||
* @returns A reference to the appended NimBLEAttValue.
|
||||
*/
|
||||
NimBLEAttValue& append(const uint8_t *value, uint16_t len);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @details Only used for types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
setValue(const T &s) {
|
||||
return setValue((uint8_t*)&s, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set value to the value of <type\>val.
|
||||
* @param [in] s The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
setValue(const T & s) {
|
||||
return setValue((uint8_t*)s.c_str(), (uint16_t)s.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to return the value as a <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than\n
|
||||
* <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is\n
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
if(!skipSizeCheck && size() < sizeof(T)) {
|
||||
return T();
|
||||
}
|
||||
return *((T *)getValue(timestamp));
|
||||
}
|
||||
|
||||
|
||||
/*********************** Operators ************************/
|
||||
|
||||
/** @brief Subscript operator */
|
||||
uint8_t operator [](int pos) const {
|
||||
assert(pos < m_attr_len && "out of range"); return m_attr_value[pos]; }
|
||||
|
||||
/** @brief Operator; Get the value as a std::vector<uint8_t>. */
|
||||
operator std::vector<uint8_t>() const {
|
||||
return std::vector<uint8_t>(m_attr_value, m_attr_value + m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a std::string. */
|
||||
operator std::string() const {
|
||||
return std::string((char*)m_attr_value, m_attr_len); }
|
||||
|
||||
/** @brief Operator; Get the value as a const uint8_t*. */
|
||||
operator const uint8_t*() const { return m_attr_value; }
|
||||
|
||||
/** @brief Operator; Append another NimBLEAttValue. */
|
||||
NimBLEAttValue& operator +=(const NimBLEAttValue & source) {
|
||||
return append(source.data(), source.size()); }
|
||||
|
||||
/** @brief Operator; Set the value from a std::string source. */
|
||||
NimBLEAttValue& operator =(const std::string & source) {
|
||||
setValue((uint8_t*)source.data(), (uint16_t)source.size()); return *this; }
|
||||
|
||||
/** @brief Move assignment operator */
|
||||
NimBLEAttValue& operator =(NimBLEAttValue && source);
|
||||
|
||||
/** @brief Copy assignment operator */
|
||||
NimBLEAttValue& operator =(const NimBLEAttValue & source);
|
||||
|
||||
/** @brief Equality operator */
|
||||
bool operator ==(const NimBLEAttValue & source) {
|
||||
return (m_attr_len == source.size()) ?
|
||||
memcmp(m_attr_value, source.data(), m_attr_len) == 0 : false; }
|
||||
|
||||
/** @brief Inequality operator */
|
||||
bool operator !=(const NimBLEAttValue & source){ return !(*this == source); }
|
||||
|
||||
#ifdef NIMBLE_CPP_ARDUINO_STRING_AVAILABLE
|
||||
/** @brief Operator; Get the value as an Arduino String value. */
|
||||
operator String() const { return String((char*)m_attr_value); }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline NimBLEAttValue::NimBLEAttValue(uint16_t init_len, uint16_t max_len) {
|
||||
m_attr_value = (uint8_t*)calloc(init_len + 1, 1);
|
||||
assert(m_attr_value && "No Mem");
|
||||
m_attr_max_len = std::min(BLE_ATT_ATTR_MAX_LEN, (int)max_len);
|
||||
m_attr_len = 0;
|
||||
m_capacity = init_len;
|
||||
setTimeStamp(0);
|
||||
}
|
||||
|
||||
inline NimBLEAttValue::NimBLEAttValue(const uint8_t *value, uint16_t len, uint16_t max_len)
|
||||
: NimBLEAttValue(len, max_len) {
|
||||
memcpy(m_attr_value, value, len);
|
||||
m_attr_value[len] = '\0';
|
||||
m_attr_len = len;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue::~NimBLEAttValue() {
|
||||
if(m_attr_value != nullptr) {
|
||||
free(m_attr_value);
|
||||
}
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::operator =(NimBLEAttValue && source) {
|
||||
if (this != &source){
|
||||
free(m_attr_value);
|
||||
|
||||
m_attr_value = source.m_attr_value;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
source.m_attr_value = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::operator =(const NimBLEAttValue & source) {
|
||||
if (this != &source) {
|
||||
deepCopy(source);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void NimBLEAttValue::deepCopy(const NimBLEAttValue & source) {
|
||||
uint8_t* res = (uint8_t*)realloc( m_attr_value, source.m_capacity + 1);
|
||||
assert(res && "deepCopy: realloc failed");
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
m_attr_max_len = source.m_attr_max_len;
|
||||
m_attr_len = source.m_attr_len;
|
||||
m_capacity = source.m_capacity;
|
||||
setTimeStamp(source.getTimeStamp());
|
||||
memcpy(m_attr_value, source.m_attr_value, m_attr_len + 1);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
}
|
||||
|
||||
inline const uint8_t* NimBLEAttValue::getValue(time_t *timestamp) {
|
||||
if(timestamp != nullptr) {
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
*timestamp = m_timestamp;
|
||||
#else
|
||||
*timestamp = 0;
|
||||
#endif
|
||||
}
|
||||
return m_attr_value;
|
||||
}
|
||||
|
||||
inline bool NimBLEAttValue::setValue(const uint8_t *value, uint16_t len) {
|
||||
if (len > m_attr_max_len) {
|
||||
NIMBLE_LOGE("NimBLEAttValue", "value exceeds max, len=%u, max=%u",
|
||||
len, m_attr_max_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *res = m_attr_value;
|
||||
if (len > m_capacity) {
|
||||
res = (uint8_t*)realloc(m_attr_value, (len + 1));
|
||||
m_capacity = len;
|
||||
}
|
||||
assert(res && "setValue: realloc failed");
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
#else
|
||||
time_t t = 0;
|
||||
#endif
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
memcpy(m_attr_value, value, len);
|
||||
m_attr_value[len] = '\0';
|
||||
m_attr_len = len;
|
||||
setTimeStamp(t);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline NimBLEAttValue& NimBLEAttValue::append(const uint8_t *value, uint16_t len) {
|
||||
if (len < 1) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if ((m_attr_len + len) > m_attr_max_len) {
|
||||
NIMBLE_LOGE("NimBLEAttValue", "val > max, len=%u, max=%u",
|
||||
len, m_attr_max_len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t* res = m_attr_value;
|
||||
uint16_t new_len = m_attr_len + len;
|
||||
if (new_len > m_capacity) {
|
||||
res = (uint8_t*)realloc(m_attr_value, (new_len + 1));
|
||||
m_capacity = new_len;
|
||||
}
|
||||
assert(res && "append: realloc failed");
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
|
||||
time_t t = time(nullptr);
|
||||
#else
|
||||
time_t t = 0;
|
||||
#endif
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
m_attr_value = res;
|
||||
memcpy(m_attr_value + m_attr_len, value, len);
|
||||
m_attr_len = new_len;
|
||||
m_attr_value[m_attr_len] = '\0';
|
||||
setTimeStamp(t);
|
||||
ble_npl_hw_exit_critical(0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif /*(CONFIG_BT_ENABLED) */
|
||||
#endif /* MAIN_NIMBLEATTVALUE_H_ */
|
||||
157
lib/NimBLE-Arduino/src/NimBLEBeacon.cpp
Normal file
157
lib/NimBLE-Arduino/src/NimBLEBeacon.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* NimBLEBeacon2.cpp
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEBeacon.cpp
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include "NimBLEBeacon.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
|
||||
static const char* LOG_TAG = "NimBLEBeacon";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a default beacon object.
|
||||
*/
|
||||
NimBLEBeacon::NimBLEBeacon() {
|
||||
m_beaconData.manufacturerId = 0x4c00;
|
||||
m_beaconData.subType = 0x02;
|
||||
m_beaconData.subTypeLength = 0x15;
|
||||
m_beaconData.major = 0;
|
||||
m_beaconData.minor = 0;
|
||||
m_beaconData.signalPower = 0;
|
||||
memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID));
|
||||
} // NimBLEBeacon
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the data that is being advertised.
|
||||
* @return The advertised data.
|
||||
*/
|
||||
std::string NimBLEBeacon::getData() {
|
||||
return std::string((char*) &m_beaconData, sizeof(m_beaconData));
|
||||
} // getData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the major value being advertised.
|
||||
* @return The major value advertised.
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getMajor() {
|
||||
return m_beaconData.major;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the manufacturer ID being advertised.
|
||||
* @return The manufacturer ID value advertised.
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getManufacturerId() {
|
||||
return m_beaconData.manufacturerId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the minor value being advertised.
|
||||
* @return minor value advertised.
|
||||
*/
|
||||
uint16_t NimBLEBeacon::getMinor() {
|
||||
return m_beaconData.minor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the proximity UUID being advertised.
|
||||
* @return The UUID advertised.
|
||||
*/
|
||||
NimBLEUUID NimBLEBeacon::getProximityUUID() {
|
||||
return NimBLEUUID(m_beaconData.proximityUUID, 16, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the signal power being advertised.
|
||||
* @return signal power level advertised.
|
||||
*/
|
||||
int8_t NimBLEBeacon::getSignalPower() {
|
||||
return m_beaconData.signalPower;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the beacon record.
|
||||
* @param [in] data The raw beacon data.
|
||||
*/
|
||||
void NimBLEBeacon::setData(const std::string &data) {
|
||||
if (data.length() != sizeof(m_beaconData)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
|
||||
data.length(), sizeof(m_beaconData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
|
||||
} // setData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the major value.
|
||||
* @param [in] major The major value.
|
||||
*/
|
||||
void NimBLEBeacon::setMajor(uint16_t major) {
|
||||
m_beaconData.major = ENDIAN_CHANGE_U16(major);
|
||||
} // setMajor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the manufacturer ID.
|
||||
* @param [in] manufacturerId The manufacturer ID value.
|
||||
*/
|
||||
void NimBLEBeacon::setManufacturerId(uint16_t manufacturerId) {
|
||||
m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId);
|
||||
} // setManufacturerId
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the minor value.
|
||||
* @param [in] minor The minor value.
|
||||
*/
|
||||
void NimBLEBeacon::setMinor(uint16_t minor) {
|
||||
m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
|
||||
} // setMinior
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the proximity UUID.
|
||||
* @param [in] uuid The proximity UUID.
|
||||
*/
|
||||
void NimBLEBeacon::setProximityUUID(const NimBLEUUID &uuid) {
|
||||
NimBLEUUID temp_uuid = uuid;
|
||||
temp_uuid.to128();
|
||||
std::reverse_copy(temp_uuid.getNative()->u128.value,
|
||||
temp_uuid.getNative()->u128.value + 16,
|
||||
m_beaconData.proximityUUID);
|
||||
} // setProximityUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the signal power.
|
||||
* @param [in] signalPower The signal power value.
|
||||
*/
|
||||
void NimBLEBeacon::setSignalPower(int8_t signalPower) {
|
||||
m_beaconData.signalPower = signalPower;
|
||||
} // setSignalPower
|
||||
|
||||
#endif
|
||||
51
lib/NimBLE-Arduino/src/NimBLEBeacon.h
Normal file
51
lib/NimBLE-Arduino/src/NimBLEBeacon.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* NimBLEBeacon2.h
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEBeacon2.h
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLEBEACON_H_
|
||||
#define MAIN_NIMBLEBEACON_H_
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://en.wikipedia.org/wiki/IBeacon
|
||||
*/
|
||||
class NimBLEBeacon {
|
||||
private:
|
||||
struct {
|
||||
uint16_t manufacturerId;
|
||||
uint8_t subType;
|
||||
uint8_t subTypeLength;
|
||||
uint8_t proximityUUID[16];
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
int8_t signalPower;
|
||||
} __attribute__((packed)) m_beaconData;
|
||||
public:
|
||||
NimBLEBeacon();
|
||||
std::string getData();
|
||||
uint16_t getMajor();
|
||||
uint16_t getMinor();
|
||||
uint16_t getManufacturerId();
|
||||
NimBLEUUID getProximityUUID();
|
||||
int8_t getSignalPower();
|
||||
void setData(const std::string &data);
|
||||
void setMajor(uint16_t major);
|
||||
void setMinor(uint16_t minor);
|
||||
void setManufacturerId(uint16_t manufacturerId);
|
||||
void setProximityUUID(const NimBLEUUID &uuid);
|
||||
void setSignalPower(int8_t signalPower);
|
||||
}; // NimBLEBeacon
|
||||
|
||||
#endif /* MAIN_NIMBLEBEACON_H_ */
|
||||
659
lib/NimBLE-Arduino/src/NimBLECharacteristic.cpp
Normal file
659
lib/NimBLE-Arduino/src/NimBLECharacteristic.cpp
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* NimBLECharacteristic.cpp
|
||||
*
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* BLECharacteristic.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLE2904.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
#define NIMBLE_SUB_NOTIFY 0x0001
|
||||
#define NIMBLE_SUB_INDICATE 0x0002
|
||||
|
||||
static NimBLECharacteristicCallbacks defaultCallback;
|
||||
static const char* LOG_TAG = "NimBLECharacteristic";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len, NimBLEService* pService)
|
||||
: NimBLECharacteristic(NimBLEUUID(uuid), properties, max_len, pService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pService - pointer to the service instance this characteristic belongs to.
|
||||
*/
|
||||
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties,
|
||||
uint16_t max_len, NimBLEService* pService)
|
||||
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = properties;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
m_pService = pService;
|
||||
m_removed = 0;
|
||||
} // NimBLECharacteristic
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
NimBLECharacteristic::~NimBLECharacteristic() {
|
||||
for(auto &it : m_dscVec) {
|
||||
delete it;
|
||||
}
|
||||
} // ~NimBLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||
* @param [in] uuid - The UUID of the descriptor.
|
||||
* @param [in] properties - The properties of the descriptor.
|
||||
* @param [in] max_len - The max length in bytes of the descriptor value.
|
||||
* @return The new BLE descriptor.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const char* uuid, uint32_t properties, uint16_t max_len) {
|
||||
return createDescriptor(NimBLEUUID(uuid), properties, max_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Descriptor associated with this characteristic.
|
||||
* @param [in] uuid - The UUID of the descriptor.
|
||||
* @param [in] properties - The properties of the descriptor.
|
||||
* @param [in] max_len - The max length in bytes of the descriptor value.
|
||||
* @return The new BLE descriptor.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||
NimBLEDescriptor* pDescriptor = nullptr;
|
||||
if(uuid == NimBLEUUID(uint16_t(0x2902))) {
|
||||
assert(0 && "0x2902 descriptors cannot be manually created");
|
||||
} else if (uuid == NimBLEUUID(uint16_t(0x2904))) {
|
||||
pDescriptor = new NimBLE2904(this);
|
||||
} else {
|
||||
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
|
||||
}
|
||||
|
||||
addDescriptor(pDescriptor);
|
||||
return pDescriptor;
|
||||
} // createDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a descriptor to the characteristic.
|
||||
* @param [in] pDescriptor A pointer to the descriptor to add.
|
||||
*/
|
||||
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
|
||||
bool foundRemoved = false;
|
||||
|
||||
if(pDescriptor->m_removed > 0) {
|
||||
for(auto& it : m_dscVec) {
|
||||
if(it == pDescriptor) {
|
||||
foundRemoved = true;
|
||||
pDescriptor->m_removed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundRemoved) {
|
||||
m_dscVec.push_back(pDescriptor);
|
||||
}
|
||||
|
||||
pDescriptor->setCharacteristic(this);
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a descriptor from the characterisitc.
|
||||
* @param[in] pDescriptor A pointer to the descriptor instance to remove from the characterisitc.
|
||||
* @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources.
|
||||
*/
|
||||
void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc) {
|
||||
// Check if the descriptor was already removed and if so, check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(pDescriptor->m_removed > 0) {
|
||||
if(deleteDsc) {
|
||||
for(auto it = m_dscVec.begin(); it != m_dscVec.end(); ++it) {
|
||||
if ((*it) == pDescriptor) {
|
||||
delete *it;
|
||||
m_dscVec.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pDescriptor->m_removed = deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
NimBLEDevice::getServer()->serviceChanged();
|
||||
} // removeDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
|
||||
return getDescriptorByUUID(NimBLEUUID(uuid));
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID.
|
||||
* @param [in] uuid The UUID of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getDescriptorByUUID
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given handle.
|
||||
* @param [in] handle The handle of the descriptor.
|
||||
* @return A pointer to the descriptor object or nullptr if not found.
|
||||
*/
|
||||
NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) {
|
||||
for (auto &it : m_dscVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle of the characteristic.
|
||||
* @return The handle of the characteristic.
|
||||
*/
|
||||
uint16_t NimBLECharacteristic::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the properties of the characteristic.
|
||||
* @return The properties of the characteristic.
|
||||
*/
|
||||
uint16_t NimBLECharacteristic::getProperties() {
|
||||
return m_properties;
|
||||
} // getProperties
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service associated with this characteristic.
|
||||
*/
|
||||
NimBLEService* NimBLECharacteristic::getService() {
|
||||
return m_pService;
|
||||
} // getService
|
||||
|
||||
|
||||
void NimBLECharacteristic::setService(NimBLEService *pService) {
|
||||
m_pService = pService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the characteristic.
|
||||
* @return The UUID of the characteristic.
|
||||
*/
|
||||
NimBLEUUID NimBLECharacteristic::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current value of the characteristic.
|
||||
* @return The NimBLEAttValue containing the current characteristic value.
|
||||
*/
|
||||
NimBLEAttValue NimBLECharacteristic::getValue(time_t *timestamp) {
|
||||
if(timestamp != nullptr) {
|
||||
m_value.getValue(timestamp);
|
||||
}
|
||||
|
||||
return m_value;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the the current data length of the characteristic.
|
||||
* @return The length of the current characteristic data.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getDataLength() {
|
||||
return m_value.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief STATIC callback to handle events from the NimBLE stack.
|
||||
*/
|
||||
int NimBLECharacteristic::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
struct ble_gap_conn_desc desc;
|
||||
NimBLECharacteristic* pCharacteristic = (NimBLECharacteristic*)arg;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Characteristic %s %s event", pCharacteristic->getUUID().toString().c_str(),
|
||||
ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ? "Read" : "Write");
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
if(ble_uuid_cmp(uuid, &pCharacteristic->getUUID().getNative()->u) == 0){
|
||||
switch(ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR: {
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic);
|
||||
pCharacteristic->m_pCallbacks->onRead(pCharacteristic, &desc);
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
rc = os_mbuf_append(ctxt->om, pCharacteristic->m_value.data(), pCharacteristic->m_value.size());
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR: {
|
||||
uint16_t att_max_len = pCharacteristic->m_value.max_size();
|
||||
|
||||
if (ctxt->om->om_len > att_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[att_max_len];
|
||||
size_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data,len);
|
||||
|
||||
os_mbuf *next;
|
||||
next = SLIST_NEXT(ctxt->om, om_next);
|
||||
while(next != NULL){
|
||||
if((len + next->om_len) > att_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
len += next->om_len;
|
||||
next = SLIST_NEXT(next, om_next);
|
||||
}
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
pCharacteristic->setValue(buf, len);
|
||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic);
|
||||
pCharacteristic->m_pCallbacks->onWrite(pCharacteristic, &desc);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of clients subscribed to the characteristic.
|
||||
* @returns Number of clients subscribed to notifications / indications.
|
||||
*/
|
||||
size_t NimBLECharacteristic::getSubscribedCount() {
|
||||
return m_subscribedVec.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the subscribe status for this characteristic.\n
|
||||
* This will maintain a vector of subscribed clients and their indicate/notify status.
|
||||
*/
|
||||
void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
|
||||
ble_gap_conn_desc desc;
|
||||
if(ble_gap_conn_find(event->subscribe.conn_handle, &desc) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t subVal = 0;
|
||||
if(event->subscribe.cur_notify > 0 && (m_properties & NIMBLE_PROPERTY::NOTIFY)) {
|
||||
subVal |= NIMBLE_SUB_NOTIFY;
|
||||
}
|
||||
if(event->subscribe.cur_indicate && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
subVal |= NIMBLE_SUB_INDICATE;
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
|
||||
event->subscribe.conn_handle, subVal);
|
||||
|
||||
if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
|
||||
NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
|
||||
}
|
||||
|
||||
|
||||
auto it = m_subscribedVec.begin();
|
||||
for(;it != m_subscribedVec.end(); ++it) {
|
||||
if((*it).first == event->subscribe.conn_handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(subVal > 0) {
|
||||
if(it == m_subscribedVec.end()) {
|
||||
m_subscribedVec.push_back({event->subscribe.conn_handle, subVal});
|
||||
} else {
|
||||
(*it).second = subVal;
|
||||
}
|
||||
} else if(it != m_subscribedVec.end()) {
|
||||
m_subscribedVec.erase(it);
|
||||
}
|
||||
|
||||
m_pCallbacks->onSubscribe(this, &desc, subVal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate() {
|
||||
notify(false);
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate(const uint8_t* value, size_t length) {
|
||||
notify(value, length, false);
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||
*/
|
||||
void NimBLECharacteristic::indicate(const std::vector<uint8_t>& value) {
|
||||
notify(value.data(), value.size(), false);
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(bool is_notification) {
|
||||
notify(m_value.data(), m_value.length(), is_notification);
|
||||
} // notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @param[in] value A std::vector<uint8_t> containing the value to send as the notification value.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(const std::vector<uint8_t>& value, bool is_notification) {
|
||||
notify(value.data(), value.size(), is_notification);
|
||||
} // notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notification or indication.
|
||||
* @param[in] value A pointer to the data to send.
|
||||
* @param[in] length The length of the data to send.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
*/
|
||||
void NimBLECharacteristic::notify(const uint8_t* value, size_t length, bool is_notification) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> notify: length: %d", length);
|
||||
|
||||
if(!(m_properties & NIMBLE_PROPERTY::NOTIFY) &&
|
||||
!(m_properties & NIMBLE_PROPERTY::INDICATE))
|
||||
{
|
||||
NIMBLE_LOGE(LOG_TAG,
|
||||
"<< notify-Error; Notify/indicate not enabled for characterisitc: %s",
|
||||
std::string(getUUID()).c_str());
|
||||
}
|
||||
|
||||
if (m_subscribedVec.size() == 0) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify: No clients subscribed.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCallbacks->onNotify(this);
|
||||
|
||||
bool reqSec = (m_properties & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||
(m_properties & BLE_GATT_CHR_F_READ_ENC);
|
||||
int rc = 0;
|
||||
|
||||
for (auto &it : m_subscribedVec) {
|
||||
uint16_t _mtu = getService()->getServer()->getPeerMTU(it.first) - 3;
|
||||
|
||||
// check if connected and subscribed
|
||||
if(_mtu == 0 || it.second == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if security requirements are satisfied
|
||||
if(reqSec) {
|
||||
struct ble_gap_conn_desc desc;
|
||||
rc = ble_gap_conn_find(it.first, &desc);
|
||||
if(rc != 0 || !desc.sec_state.encrypted) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (length > _mtu) {
|
||||
NIMBLE_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu);
|
||||
}
|
||||
|
||||
if(is_notification && (!(it.second & NIMBLE_SUB_NOTIFY))) {
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"Sending notification to client subscribed to indications, sending indication instead");
|
||||
is_notification = false;
|
||||
}
|
||||
|
||||
if(!is_notification && (!(it.second & NIMBLE_SUB_INDICATE))) {
|
||||
NIMBLE_LOGW(LOG_TAG,
|
||||
"Sending indication to client subscribed to notification, sending notification instead");
|
||||
is_notification = true;
|
||||
}
|
||||
|
||||
// don't create the m_buf until we are sure to send the data or else
|
||||
// we could be allocating a buffer that doesn't get released.
|
||||
// We also must create it in each loop iteration because it is consumed with each host call.
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(value, length);
|
||||
|
||||
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
|
||||
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
|
||||
os_mbuf_free_chain(om);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_gattc_indicate_custom(it.first, m_handle, om);
|
||||
if(rc != 0){
|
||||
NimBLEDevice::getServer()->clearIndicateWait(it.first);
|
||||
}
|
||||
} else {
|
||||
ble_gattc_notify_custom(it.first, m_handle, om);
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< notify");
|
||||
} // Notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callback handlers for this characteristic.
|
||||
* @param [in] pCallbacks An instance of a NimBLECharacteristicCallbacks class\n
|
||||
* used to define any callbacks for the characteristic.
|
||||
*/
|
||||
void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallbacks) {
|
||||
if (pCallbacks != nullptr){
|
||||
m_pCallbacks = pCallbacks;
|
||||
} else {
|
||||
m_pCallbacks = &defaultCallback;
|
||||
}
|
||||
} // setCallbacks
|
||||
|
||||
/**
|
||||
* @brief Get the callback handlers for this characteristic.
|
||||
*/
|
||||
NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
|
||||
return m_pCallbacks;
|
||||
} //getCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from a data buffer .
|
||||
* @param [in] data The data buffer to set for the characteristic.
|
||||
* @param [in] length The number of bytes in the data buffer.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const uint8_t* data, size_t length) {
|
||||
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
char* pHex = NimBLEUtils::buildHexData(nullptr, data, length);
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s",
|
||||
length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
#endif
|
||||
|
||||
m_value.setValue(data, length);
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from a `std::vector<uint8_t>`.\n
|
||||
* @param [in] vec The std::vector<uint8_t> reference to set the characteristic value from.
|
||||
*/
|
||||
void NimBLECharacteristic::setValue(const std::vector<uint8_t>& vec) {
|
||||
return setValue((uint8_t*)&vec[0], vec.size());
|
||||
}// setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the characteristic.
|
||||
* @return A string representation of the characteristic.
|
||||
*/
|
||||
std::string NimBLECharacteristic::toString() {
|
||||
std::string res = "UUID: " + m_uuid.toString() + ", handle : 0x";
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", m_handle);
|
||||
res += hex;
|
||||
res += " ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_READ ) res += "Read ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_WRITE) res += "Write ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_WRITE_NO_RSP) res += "WriteNoResponse ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_BROADCAST) res += "Broadcast ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_NOTIFY) res += "Notify ";
|
||||
if (m_properties & BLE_GATT_CHR_PROP_INDICATE) res += "Indicate ";
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
NimBLECharacteristicCallbacks::~NimBLECharacteristicCallbacks() {}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] desc The connection description struct that is associated with the peer that performed the read.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] desc The connection description struct that is associated with the peer that performed the write.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onNotify(NimBLECharacteristic* pCharacteristic) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onNotify: default");
|
||||
} // onNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify/Indicate Status report.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] s Status of the notification/indication.
|
||||
* @param [in] code Additional return code from the NimBLE stack.
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code) {
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onStatus: default");
|
||||
} // onStatus
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function called when a client changes subscription status.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] desc The connection description struct that is associated with the client.
|
||||
* @param [in] subValue The subscription status:
|
||||
* * 0 = Un-Subscribed
|
||||
* * 1 = Notifications
|
||||
* * 2 = Indications
|
||||
* * 3 = Notifications and Indications
|
||||
*/
|
||||
void NimBLECharacteristicCallbacks::onSubscribe(NimBLECharacteristic* pCharacteristic,
|
||||
ble_gap_conn_desc* desc,
|
||||
uint16_t subValue)
|
||||
{
|
||||
NIMBLE_LOGD("NimBLECharacteristicCallbacks", "onSubscribe: default");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
231
lib/NimBLE-Arduino/src/NimBLECharacteristic.h
Normal file
231
lib/NimBLE-Arduino/src/NimBLECharacteristic.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* NimBLECharacteristic.h
|
||||
*
|
||||
* Created: on March 3, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
* BLECharacteristic.h
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#define MAIN_NIMBLECHARACTERISTIC_H_
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_hs.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_hs.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
typedef enum {
|
||||
READ = BLE_GATT_CHR_F_READ,
|
||||
READ_ENC = BLE_GATT_CHR_F_READ_ENC,
|
||||
READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
|
||||
READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
|
||||
WRITE = BLE_GATT_CHR_F_WRITE,
|
||||
WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC,
|
||||
WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN,
|
||||
WRITE_AUTHOR = BLE_GATT_CHR_F_WRITE_AUTHOR,
|
||||
BROADCAST = BLE_GATT_CHR_F_BROADCAST,
|
||||
NOTIFY = BLE_GATT_CHR_F_NOTIFY,
|
||||
INDICATE = BLE_GATT_CHR_F_INDICATE
|
||||
} NIMBLE_PROPERTY;
|
||||
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLEDescriptor;
|
||||
class NimBLECharacteristicCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE Characteristic.
|
||||
*
|
||||
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and
|
||||
* can be read and written to by a %BLE client.
|
||||
*/
|
||||
class NimBLECharacteristic {
|
||||
public:
|
||||
NimBLECharacteristic(const char* uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||
NimBLEService* pService = nullptr);
|
||||
NimBLECharacteristic(const NimBLEUUID &uuid,
|
||||
uint16_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN,
|
||||
NimBLEService* pService = nullptr);
|
||||
|
||||
~NimBLECharacteristic();
|
||||
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
void indicate();
|
||||
void indicate(const uint8_t* value, size_t length);
|
||||
void indicate(const std::vector<uint8_t>& value);
|
||||
void notify(bool is_notification = true);
|
||||
void notify(const uint8_t* value, size_t length, bool is_notification = true);
|
||||
void notify(const std::vector<uint8_t>& value, bool is_notification = true);
|
||||
size_t getSubscribedCount();
|
||||
void addDescriptor(NimBLEDescriptor *pDescriptor);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
|
||||
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
|
||||
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
|
||||
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
|
||||
NimBLEService* getService();
|
||||
uint16_t getProperties();
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
size_t getDataLength();
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::vector<uint8_t>& vec);
|
||||
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
|
||||
NimBLEDescriptor* createDescriptor(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);;
|
||||
NimBLEDescriptor* createDescriptor(const NimBLEUUID &uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
NimBLECharacteristicCallbacks* getCallbacks();
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||
|
||||
/**
|
||||
* @brief Template to convert the characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send a notification from a class type that has a c_str() and length() method.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @param[in] is_notification if true sends a notification, false sends an indication.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||
#endif
|
||||
notify(const T& value, bool is_notification = true) {
|
||||
notify((uint8_t*)value.c_str(), value.length(), is_notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to send an indication from a class type that has a c_str() and length() method.
|
||||
* @tparam T The a reference to a class containing the data to send.
|
||||
* @param[in] value The <type\>value to set.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, void>::type
|
||||
#endif
|
||||
indicate(const T& value) {
|
||||
indicate((uint8_t*)value.c_str(), value.length());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEService;
|
||||
|
||||
void setService(NimBLEService *pService);
|
||||
void setSubscribe(struct ble_gap_event *event);
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_handle;
|
||||
uint16_t m_properties;
|
||||
NimBLECharacteristicCallbacks* m_pCallbacks;
|
||||
NimBLEService* m_pService;
|
||||
NimBLEAttValue m_value;
|
||||
std::vector<NimBLEDescriptor*> m_dscVec;
|
||||
uint8_t m_removed;
|
||||
|
||||
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
|
||||
}; // NimBLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
|
||||
*
|
||||
* When a server application creates a %BLE characteristic, we may wish to be informed when there is either
|
||||
* a read or write request to the characteristic's value. An application can register a
|
||||
* sub-classed instance of this class and will be notified when such an event happens.
|
||||
*/
|
||||
class NimBLECharacteristicCallbacks {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief An enum to provide the callback the status of the
|
||||
* notification/indication, implemented for backward compatibility.
|
||||
* @deprecated To be removed in the future as the NimBLE stack return code is also provided.
|
||||
*/
|
||||
typedef enum {
|
||||
SUCCESS_INDICATE,
|
||||
SUCCESS_NOTIFY,
|
||||
ERROR_INDICATE_DISABLED,
|
||||
ERROR_NOTIFY_DISABLED,
|
||||
ERROR_GATT,
|
||||
ERROR_NO_CLIENT,
|
||||
ERROR_INDICATE_TIMEOUT,
|
||||
ERROR_INDICATE_FAILURE
|
||||
}Status;
|
||||
|
||||
virtual ~NimBLECharacteristicCallbacks();
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onRead(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onWrite(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc);
|
||||
virtual void onNotify(NimBLECharacteristic* pCharacteristic);
|
||||
virtual void onStatus(NimBLECharacteristic* pCharacteristic, Status s, int code);
|
||||
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /*MAIN_NIMBLECHARACTERISTIC_H_*/
|
||||
1247
lib/NimBLE-Arduino/src/NimBLEClient.cpp
Normal file
1247
lib/NimBLE-Arduino/src/NimBLEClient.cpp
Normal file
File diff suppressed because it is too large
Load Diff
163
lib/NimBLE-Arduino/src/NimBLEClient.h
Normal file
163
lib/NimBLE-Arduino/src/NimBLEClient.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* NimBLEClient.h
|
||||
*
|
||||
* Created: on Jan 26 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
* BLEClient.h
|
||||
*
|
||||
* Created on: Mar 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLECLIENT_H_
|
||||
#define MAIN_NIMBLECLIENT_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#include "NimBLERemoteService.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class NimBLERemoteService;
|
||||
class NimBLERemoteCharacteristic;
|
||||
class NimBLEClientCallbacks;
|
||||
class NimBLEAdvertisedDevice;
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE client.
|
||||
*/
|
||||
class NimBLEClient {
|
||||
public:
|
||||
bool connect(NimBLEAdvertisedDevice* device, bool deleteAttibutes = true);
|
||||
bool connect(const NimBLEAddress &address, bool deleteAttibutes = true);
|
||||
bool connect(bool deleteAttibutes = true);
|
||||
int disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
NimBLEAddress getPeerAddress();
|
||||
void setPeerAddress(const NimBLEAddress &address);
|
||||
int getRssi();
|
||||
std::vector<NimBLERemoteService*>* getServices(bool refresh = false);
|
||||
std::vector<NimBLERemoteService*>::iterator begin();
|
||||
std::vector<NimBLERemoteService*>::iterator end();
|
||||
NimBLERemoteService* getService(const char* uuid);
|
||||
NimBLERemoteService* getService(const NimBLEUUID &uuid);
|
||||
void deleteServices();
|
||||
size_t deleteService(const NimBLEUUID &uuid);
|
||||
NimBLEAttValue getValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID);
|
||||
bool setValue(const NimBLEUUID &serviceUUID, const NimBLEUUID &characteristicUUID,
|
||||
const NimBLEAttValue &value, bool response = false);
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const uint16_t handle);
|
||||
bool isConnected();
|
||||
void setClientCallbacks(NimBLEClientCallbacks *pClientCallbacks,
|
||||
bool deleteCallbacks = true);
|
||||
std::string toString();
|
||||
uint16_t getConnId();
|
||||
uint16_t getMTU();
|
||||
bool secureConnection();
|
||||
void setConnectTimeout(uint8_t timeout);
|
||||
void setConnectionParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout,
|
||||
uint16_t scanInterval=16, uint16_t scanWindow=16);
|
||||
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
void setDataLen(uint16_t tx_octets);
|
||||
void discoverAttributes();
|
||||
NimBLEConnInfo getConnInfo();
|
||||
int getLastError();
|
||||
|
||||
private:
|
||||
NimBLEClient(const NimBLEAddress &peerAddress);
|
||||
~NimBLEClient();
|
||||
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLERemoteService;
|
||||
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
static int serviceDiscoveredCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service,
|
||||
void *arg);
|
||||
static void dcTimerCb(ble_npl_event *event);
|
||||
bool retrieveServices(const NimBLEUUID *uuid_filter = nullptr);
|
||||
|
||||
NimBLEAddress m_peerAddress;
|
||||
int m_lastErr;
|
||||
uint16_t m_conn_id;
|
||||
bool m_connEstablished;
|
||||
bool m_deleteCallbacks;
|
||||
int32_t m_connectTimeout;
|
||||
NimBLEClientCallbacks* m_pClientCallbacks;
|
||||
ble_task_data_t* m_pTaskData;
|
||||
ble_npl_callout m_dcTimer;
|
||||
|
||||
std::vector<NimBLERemoteService*> m_servicesVector;
|
||||
|
||||
private:
|
||||
friend class NimBLEClientCallbacks;
|
||||
ble_gap_conn_params m_pConnParams;
|
||||
|
||||
}; // class NimBLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks associated with a %BLE client.
|
||||
*/
|
||||
class NimBLEClientCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEClientCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Called after client connects.
|
||||
* @param [in] pClient A pointer to the calling client object.
|
||||
*/
|
||||
virtual void onConnect(NimBLEClient* pClient);
|
||||
|
||||
/**
|
||||
* @brief Called when disconnected from the server.
|
||||
* @param [in] pClient A pointer to the calling client object.
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEClient* pClient);
|
||||
|
||||
/**
|
||||
* @brief Called when server requests to update the connection parameters.
|
||||
* @param [in] pClient A pointer to the calling client object.
|
||||
* @param [in] params A pointer to the struct containing the connection parameters requested.
|
||||
* @return True to accept the parmeters.
|
||||
*/
|
||||
virtual bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params);
|
||||
|
||||
/**
|
||||
* @brief Called when server requests a passkey for pairing.
|
||||
* @return The passkey to be sent to the server.
|
||||
*/
|
||||
virtual uint32_t onPassKeyRequest();
|
||||
|
||||
/*virtual void onPassKeyNotify(uint32_t pass_key);
|
||||
virtual bool onSecurityRequest();*/
|
||||
|
||||
/**
|
||||
* @brief Called when the pairing procedure is complete.
|
||||
* @param [in] desc A pointer to the struct containing the connection information.\n
|
||||
* This can be used to check the status of the connection encryption/pairing.
|
||||
*/
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when using numeric comparision for pairing.
|
||||
* @param [in] pin The pin to compare with the server.
|
||||
* @return True to accept the pin.
|
||||
*/
|
||||
virtual bool onConfirmPIN(uint32_t pin);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* MAIN_NIMBLECLIENT_H_ */
|
||||
55
lib/NimBLE-Arduino/src/NimBLEConnInfo.h
Normal file
55
lib/NimBLE-Arduino/src/NimBLEConnInfo.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef NIMBLECONNINFO_H_
|
||||
#define NIMBLECONNINFO_H_
|
||||
|
||||
#include "NimBLEAddress.h"
|
||||
|
||||
/**
|
||||
* @brief Connection information.
|
||||
*/
|
||||
class NimBLEConnInfo {
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEClient;
|
||||
ble_gap_conn_desc m_desc;
|
||||
NimBLEConnInfo() { m_desc = {}; }
|
||||
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
|
||||
public:
|
||||
/** @brief Gets the over-the-air address of the connected peer */
|
||||
NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
|
||||
|
||||
/** @brief Gets the ID address of the connected peer */
|
||||
NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
|
||||
|
||||
/** @brief Gets the connection handle of the connected peer */
|
||||
uint16_t getConnHandle() { return m_desc.conn_handle; }
|
||||
|
||||
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
|
||||
uint16_t getConnInterval() { return m_desc.conn_itvl; }
|
||||
|
||||
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
|
||||
uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
|
||||
|
||||
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
|
||||
uint16_t getConnLatency() { return m_desc.conn_latency; }
|
||||
|
||||
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
|
||||
uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
|
||||
|
||||
/** @brief Check if we are in the master role in this connection */
|
||||
bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
|
||||
|
||||
/** @brief Check if we are in the slave role in this connection */
|
||||
bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
|
||||
|
||||
/** @brief Check if we are connected to a bonded peer */
|
||||
bool isBonded() { return (m_desc.sec_state.bonded == 1); }
|
||||
|
||||
/** @brief Check if the connection in encrypted */
|
||||
bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
|
||||
|
||||
/** @brief Check if the the connection has been authenticated */
|
||||
bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
|
||||
|
||||
/** @brief Gets the key size used to encrypt the connection */
|
||||
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
|
||||
};
|
||||
#endif
|
||||
299
lib/NimBLE-Arduino/src/NimBLEDescriptor.cpp
Normal file
299
lib/NimBLE-Arduino/src/NimBLEDescriptor.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* NimBLEDescriptor.cpp
|
||||
*
|
||||
* Created: on March 10, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEDescriptor.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
static const char* LOG_TAG = "NimBLEDescriptor";
|
||||
static NimBLEDescriptorCallbacks defaultCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a descriptor
|
||||
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||
* @param [in] properties - Properties for the descriptor.
|
||||
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||
*/
|
||||
NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic)
|
||||
: NimBLEDescriptor(NimBLEUUID(uuid), properties, max_len, pCharacteristic) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a descriptor
|
||||
* @param [in] uuid - UUID (const char*) for the descriptor.
|
||||
* @param [in] properties - Properties for the descriptor.
|
||||
* @param [in] max_len - The maximum length in bytes that the descriptor value can hold. (Default: 512 bytes for esp32, 20 for all others).
|
||||
* @param [in] pCharacteristic - pointer to the characteristic instance this descriptor belongs to.
|
||||
*/
|
||||
NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic)
|
||||
: m_value(std::min(CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH , (int)max_len), max_len) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||
m_pCharacteristic = pCharacteristic;
|
||||
m_pCallbacks = &defaultCallbacks; // No initial callback.
|
||||
m_properties = 0;
|
||||
m_removed = 0;
|
||||
|
||||
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
|
||||
m_properties |= BLE_ATT_F_READ;
|
||||
}
|
||||
if (properties & (BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE)) {
|
||||
m_properties |= BLE_ATT_F_WRITE;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_READ_ENC) {
|
||||
m_properties |= BLE_ATT_F_READ_ENC;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_READ_AUTHEN) {
|
||||
m_properties |= BLE_ATT_F_READ_AUTHEN;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_READ_AUTHOR) {
|
||||
m_properties |= BLE_ATT_F_READ_AUTHOR;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_WRITE_ENC) {
|
||||
m_properties |= BLE_ATT_F_WRITE_ENC;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_WRITE_AUTHEN) {
|
||||
m_properties |= BLE_ATT_F_WRITE_AUTHEN;
|
||||
}
|
||||
if (properties & BLE_GATT_CHR_F_WRITE_AUTHOR) {
|
||||
m_properties |= BLE_ATT_F_WRITE_AUTHOR;
|
||||
}
|
||||
|
||||
} // NimBLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief NimBLEDescriptor destructor.
|
||||
*/
|
||||
NimBLEDescriptor::~NimBLEDescriptor() {
|
||||
} // ~NimBLEDescriptor
|
||||
|
||||
/**
|
||||
* @brief Get the BLE handle for this descriptor.
|
||||
* @return The handle for this descriptor.
|
||||
*/
|
||||
uint16_t NimBLEDescriptor::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the value of this descriptor.
|
||||
* @return The length (in bytes) of the value of this descriptor.
|
||||
*/
|
||||
size_t NimBLEDescriptor::getLength() {
|
||||
return m_value.size();
|
||||
} // getLength
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the descriptor.
|
||||
*/
|
||||
NimBLEUUID NimBLEDescriptor::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of this descriptor.
|
||||
* @return The NimBLEAttValue of this descriptor.
|
||||
*/
|
||||
NimBLEAttValue NimBLEDescriptor::getValue(time_t *timestamp) {
|
||||
if (timestamp != nullptr) {
|
||||
m_value.getValue(timestamp);
|
||||
}
|
||||
|
||||
return m_value;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of this descriptor as a string.
|
||||
* @return A std::string instance containing a copy of the descriptor's value.
|
||||
*/
|
||||
std::string NimBLEDescriptor::getStringValue() {
|
||||
return std::string(m_value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic this descriptor belongs to.
|
||||
* @return A pointer to the characteristic this descriptor belongs to.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() {
|
||||
return m_pCharacteristic;
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
(void)conn_handle;
|
||||
(void)attr_handle;
|
||||
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Descriptor %s %s event", pDescriptor->getUUID().toString().c_str(),
|
||||
ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC ? "Read" : "Write");
|
||||
|
||||
uuid = ctxt->chr->uuid;
|
||||
if(ble_uuid_cmp(uuid, &pDescriptor->getUUID().getNative()->u) == 0){
|
||||
switch(ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC: {
|
||||
// If the packet header is only 8 bytes this is a follow up of a long read
|
||||
// so we don't want to call the onRead() callback again.
|
||||
if(ctxt->om->om_pkthdr_len > 8) {
|
||||
pDescriptor->m_pCallbacks->onRead(pDescriptor);
|
||||
}
|
||||
|
||||
ble_npl_hw_enter_critical();
|
||||
rc = os_mbuf_append(ctxt->om, pDescriptor->m_value.data(), pDescriptor->m_value.size());
|
||||
ble_npl_hw_exit_critical(0);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC: {
|
||||
uint16_t att_max_len = pDescriptor->m_value.max_size();
|
||||
|
||||
if (ctxt->om->om_len > att_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
uint8_t buf[att_max_len];
|
||||
size_t len = ctxt->om->om_len;
|
||||
memcpy(buf, ctxt->om->om_data,len);
|
||||
os_mbuf *next;
|
||||
next = SLIST_NEXT(ctxt->om, om_next);
|
||||
while(next != NULL){
|
||||
if((len + next->om_len) > att_max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
memcpy(&buf[len], next->om_data, next->om_len);
|
||||
len += next->om_len;
|
||||
next = SLIST_NEXT(next, om_next);
|
||||
}
|
||||
|
||||
pDescriptor->setValue(buf, len);
|
||||
pDescriptor->m_pCallbacks->onWrite(pDescriptor);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the callback handlers for this descriptor.
|
||||
* @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor.
|
||||
*/
|
||||
void NimBLEDescriptor::setCallbacks(NimBLEDescriptorCallbacks* pCallbacks) {
|
||||
if (pCallbacks != nullptr){
|
||||
m_pCallbacks = pCallbacks;
|
||||
} else {
|
||||
m_pCallbacks = &defaultCallbacks;
|
||||
}
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the handle of this descriptor.
|
||||
* Set the handle of this descriptor to be the supplied value.
|
||||
* @param [in] handle The handle to be associated with this descriptor.
|
||||
* @return N/A.
|
||||
*/
|
||||
void NimBLEDescriptor::setHandle(uint16_t handle) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
|
||||
m_handle = handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setHandle()");
|
||||
} // setHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the descriptor.
|
||||
* @param [in] data The data to set for the descriptor.
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void NimBLEDescriptor::setValue(const uint8_t* data, size_t length) {
|
||||
m_value.setValue(data, length);
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the descriptor from a `std::vector<uint8_t>`.\n
|
||||
* @param [in] vec The std::vector<uint8_t> reference to set the descriptor value from.
|
||||
*/
|
||||
void NimBLEDescriptor::setValue(const std::vector<uint8_t>& vec) {
|
||||
return setValue((uint8_t*)&vec[0], vec.size());
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic this descriptor belongs to.
|
||||
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
|
||||
*/
|
||||
void NimBLEDescriptor::setCharacteristic(NimBLECharacteristic* pChar) {
|
||||
m_pCharacteristic = pChar;
|
||||
} // setCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor.
|
||||
* @return A string representation of the descriptor.
|
||||
*/
|
||||
std::string NimBLEDescriptor::toString() {
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", m_handle);
|
||||
std::string res = "UUID: " + m_uuid.toString() + ", handle: 0x" + hex;
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
NimBLEDescriptorCallbacks::~NimBLEDescriptorCallbacks() {}
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void NimBLEDescriptorCallbacks::onRead(NimBLEDescriptor* pDescriptor) {
|
||||
(void)pDescriptor;
|
||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onRead: default");
|
||||
} // onRead
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor) {
|
||||
(void)pDescriptor;
|
||||
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
|
||||
} // onWrite
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
119
lib/NimBLE-Arduino/src/NimBLEDescriptor.h
Normal file
119
lib/NimBLE-Arduino/src/NimBLEDescriptor.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* NimBLEDescriptor.h
|
||||
*
|
||||
* Created: on March 10, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEDescriptor.h
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLEDESCRIPTOR_H_
|
||||
#define MAIN_NIMBLEDESCRIPTOR_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLEAttValue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
class NimBLEDescriptorCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE descriptor.
|
||||
*/
|
||||
class NimBLEDescriptor {
|
||||
public:
|
||||
NimBLEDescriptor(const char* uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic = nullptr);
|
||||
|
||||
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
|
||||
uint16_t max_len,
|
||||
NimBLECharacteristic* pCharacteristic = nullptr);
|
||||
|
||||
~NimBLEDescriptor();
|
||||
|
||||
uint16_t getHandle();
|
||||
NimBLEUUID getUUID();
|
||||
std::string toString();
|
||||
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
|
||||
NimBLECharacteristic* getCharacteristic();
|
||||
|
||||
size_t getLength();
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
std::string getStringValue();
|
||||
|
||||
void setValue(const uint8_t* data, size_t size);
|
||||
void setValue(const std::vector<uint8_t>& vec);
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set the characteristic value to <type\>val.
|
||||
* @param [in] s The value to set.
|
||||
*/
|
||||
template<typename T>
|
||||
void setValue(const T &s) { m_value.setValue<T>(s); }
|
||||
|
||||
/**
|
||||
* @brief Template to convert the descriptor data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp (Optional) A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
return m_value.getValue<T>(timestamp, skipSizeCheck);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLE2904;
|
||||
|
||||
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
void setHandle(uint16_t handle);
|
||||
void setCharacteristic(NimBLECharacteristic* pChar);
|
||||
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_handle;
|
||||
NimBLEDescriptorCallbacks* m_pCallbacks;
|
||||
NimBLECharacteristic* m_pCharacteristic;
|
||||
uint8_t m_properties;
|
||||
NimBLEAttValue m_value;
|
||||
uint8_t m_removed;
|
||||
}; // NimBLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE descriptors to inform of events.
|
||||
*
|
||||
* When a server application creates a %BLE descriptor, we may wish to be informed when there is either
|
||||
* a read or write request to the descriptors value. An application can register a
|
||||
* sub-classed instance of this class and will be notified when such an event happens.
|
||||
*/
|
||||
class NimBLEDescriptorCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEDescriptorCallbacks();
|
||||
virtual void onRead(NimBLEDescriptor* pDescriptor);
|
||||
virtual void onWrite(NimBLEDescriptor* pDescriptor);
|
||||
};
|
||||
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLEDESCRIPTOR_H_ */
|
||||
1159
lib/NimBLE-Arduino/src/NimBLEDevice.cpp
Normal file
1159
lib/NimBLE-Arduino/src/NimBLEDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
218
lib/NimBLE-Arduino/src/NimBLEDevice.h
Normal file
218
lib/NimBLE-Arduino/src/NimBLEDevice.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* NimBLEDevice.h
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEDevice.h
|
||||
*
|
||||
* Created on: Mar 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLEDEVICE_H_
|
||||
#define MAIN_NIMBLEDEVICE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
#include "NimBLEScan.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
#include "NimBLEAdvertising.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
#include "NimBLEClient.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
#include "NimBLEServer.h"
|
||||
#endif
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEAddress.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
# include "esp_bt.h"
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#define BLEDevice NimBLEDevice
|
||||
#define BLEClient NimBLEClient
|
||||
#define BLERemoteService NimBLERemoteService
|
||||
#define BLERemoteCharacteristic NimBLERemoteCharacteristic
|
||||
#define BLERemoteDescriptor NimBLERemoteDescriptor
|
||||
#define BLEAdvertisedDevice NimBLEAdvertisedDevice
|
||||
#define BLEScan NimBLEScan
|
||||
#define BLEUUID NimBLEUUID
|
||||
#define BLESecurity NimBLESecurity
|
||||
#define BLESecurityCallbacks NimBLESecurityCallbacks
|
||||
#define BLEAddress NimBLEAddress
|
||||
#define BLEUtils NimBLEUtils
|
||||
#define BLEClientCallbacks NimBLEClientCallbacks
|
||||
#define BLEAdvertisedDeviceCallbacks NimBLEAdvertisedDeviceCallbacks
|
||||
#define BLEScanResults NimBLEScanResults
|
||||
#define BLEServer NimBLEServer
|
||||
#define BLEService NimBLEService
|
||||
#define BLECharacteristic NimBLECharacteristic
|
||||
#define BLEAdvertising NimBLEAdvertising
|
||||
#define BLEServerCallbacks NimBLEServerCallbacks
|
||||
#define BLECharacteristicCallbacks NimBLECharacteristicCallbacks
|
||||
#define BLEAdvertisementData NimBLEAdvertisementData
|
||||
#define BLEDescriptor NimBLEDescriptor
|
||||
#define BLE2902 NimBLE2902
|
||||
#define BLE2904 NimBLE2904
|
||||
#define BLEDescriptorCallbacks NimBLEDescriptorCallbacks
|
||||
#define BLEBeacon NimBLEBeacon
|
||||
#define BLEEddystoneTLM NimBLEEddystoneTLM
|
||||
#define BLEEddystoneURL NimBLEEddystoneURL
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
#define NIMBLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
#else
|
||||
#define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
|
||||
#endif
|
||||
|
||||
typedef int (*gap_event_handler)(ble_gap_event *event, void *arg);
|
||||
|
||||
extern "C" void ble_store_config_init(void);
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE Device from which all the BLE roles are created.
|
||||
*/
|
||||
class NimBLEDevice {
|
||||
public:
|
||||
static void init(const std::string &deviceName);
|
||||
static void deinit(bool clearAll = false);
|
||||
static bool getInitialized();
|
||||
static NimBLEAddress getAddress();
|
||||
static std::string toString();
|
||||
static bool whiteListAdd(const NimBLEAddress & address);
|
||||
static bool whiteListRemove(const NimBLEAddress & address);
|
||||
static bool onWhiteList(const NimBLEAddress & address);
|
||||
static size_t getWhiteListCount();
|
||||
static NimBLEAddress getWhiteListAddress(size_t index);
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
static NimBLEScan* getScan();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static NimBLEServer* createServer();
|
||||
static NimBLEServer* getServer();
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
|
||||
static void setOwnAddrType(uint8_t own_addr_type, bool useNRPA=false);
|
||||
static void setScanDuplicateCacheSize(uint16_t cacheSize);
|
||||
static void setScanFilterMode(uint8_t type);
|
||||
#else
|
||||
static void setPower(int dbm);
|
||||
static int getPower();
|
||||
#endif
|
||||
|
||||
static void setCustomGapHandler(gap_event_handler handler);
|
||||
static void setSecurityAuth(bool bonding, bool mitm, bool sc);
|
||||
static void setSecurityAuth(uint8_t auth_req);
|
||||
static void setSecurityIOCap(uint8_t iocap);
|
||||
static void setSecurityInitKey(uint8_t init_key);
|
||||
static void setSecurityRespKey(uint8_t init_key);
|
||||
static void setSecurityPasskey(uint32_t pin);
|
||||
static uint32_t getSecurityPasskey();
|
||||
static void setSecurityCallbacks(NimBLESecurityCallbacks* pCallbacks);
|
||||
static int startSecurity(uint16_t conn_id);
|
||||
static int setMTU(uint16_t mtu);
|
||||
static uint16_t getMTU();
|
||||
static bool isIgnored(const NimBLEAddress &address);
|
||||
static void addIgnored(const NimBLEAddress &address);
|
||||
static void removeIgnored(const NimBLEAddress &address);
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
static NimBLEAdvertising* getAdvertising();
|
||||
static void startAdvertising();
|
||||
static void stopAdvertising();
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
static NimBLEClient* createClient(NimBLEAddress peerAddress = NimBLEAddress(""));
|
||||
static bool deleteClient(NimBLEClient* pClient);
|
||||
static NimBLEClient* getClientByID(uint16_t conn_id);
|
||||
static NimBLEClient* getClientByPeerAddress(const NimBLEAddress &peer_addr);
|
||||
static NimBLEClient* getDisconnectedClient();
|
||||
static size_t getClientListSize();
|
||||
static std::list<NimBLEClient*>* getClientList();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static bool deleteBond(const NimBLEAddress &address);
|
||||
static int getNumBonds();
|
||||
static bool isBonded(const NimBLEAddress &address);
|
||||
static void deleteAllBonds();
|
||||
static NimBLEAddress getBondedAddress(int index);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
friend class NimBLEClient;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
friend class NimBLEScan;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLECharacteristic;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
friend class NimBLEAdvertising;
|
||||
#endif
|
||||
|
||||
static void onReset(int reason);
|
||||
static void onSync(void);
|
||||
static void host_task(void *param);
|
||||
static bool m_synced;
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
static NimBLEScan* m_pScan;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
static NimBLEServer* m_pServer;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
static NimBLEAdvertising* m_bleAdvertising;
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
static std::list <NimBLEClient*> m_cList;
|
||||
#endif
|
||||
static std::list <NimBLEAddress> m_ignoreList;
|
||||
static NimBLESecurityCallbacks* m_securityCallbacks;
|
||||
static uint32_t m_passkey;
|
||||
static ble_gap_event_listener m_listener;
|
||||
static gap_event_handler m_customGapHandler;
|
||||
static uint8_t m_own_addr_type;
|
||||
#ifdef ESP_PLATFORM
|
||||
static uint16_t m_scanDuplicateSize;
|
||||
static uint8_t m_scanFilterMode;
|
||||
#endif
|
||||
static std::vector<NimBLEAddress> m_whiteList;
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // MAIN_NIMBLEDEVICE_H_
|
||||
227
lib/NimBLE-Arduino/src/NimBLEEddystoneTLM.cpp
Normal file
227
lib/NimBLE-Arduino/src/NimBLEEddystoneTLM.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* NimBLEEddystoneTLM.cpp
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEEddystoneTLM.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEEddystoneTLM.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24))
|
||||
|
||||
static const char LOG_TAG[] = "NimBLEEddystoneTLM";
|
||||
|
||||
/**
|
||||
* @brief Construct a default EddystoneTLM beacon object.
|
||||
*/
|
||||
NimBLEEddystoneTLM::NimBLEEddystoneTLM() {
|
||||
beaconUUID = 0xFEAA;
|
||||
m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
|
||||
m_eddystoneData.version = 0;
|
||||
m_eddystoneData.volt = 3300; // 3300mV = 3.3V
|
||||
m_eddystoneData.temp = (uint16_t) ((float) 23.00 * 256); // 8.8 fixed format
|
||||
m_eddystoneData.advCount = 0;
|
||||
m_eddystoneData.tmil = 0;
|
||||
} // NimBLEEddystoneTLM
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the data that is being advertised.
|
||||
* @return The advertised data.
|
||||
*/
|
||||
std::string NimBLEEddystoneTLM::getData() {
|
||||
return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
|
||||
} // getData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID being advertised.
|
||||
* @return The UUID advertised.
|
||||
*/
|
||||
NimBLEUUID NimBLEEddystoneTLM::getUUID() {
|
||||
return NimBLEUUID(beaconUUID);
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the version being advertised.
|
||||
* @return The version number.
|
||||
*/
|
||||
uint8_t NimBLEEddystoneTLM::getVersion() {
|
||||
return m_eddystoneData.version;
|
||||
} // getVersion
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the battery voltage.
|
||||
* @return The battery voltage.
|
||||
*/
|
||||
uint16_t NimBLEEddystoneTLM::getVolt() {
|
||||
return ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
} // getVolt
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the temperature being advertised.
|
||||
* @return The temperature value.
|
||||
*/
|
||||
float NimBLEEddystoneTLM::getTemp() {
|
||||
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
|
||||
} // getTemp
|
||||
|
||||
/**
|
||||
* @brief Get the count of advertisments sent.
|
||||
* @return The number of advertisments.
|
||||
*/
|
||||
uint32_t NimBLEEddystoneTLM::getCount() {
|
||||
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||
} // getCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the advertisment time.
|
||||
* @return The advertisment time.
|
||||
*/
|
||||
uint32_t NimBLEEddystoneTLM::getTime() {
|
||||
return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
|
||||
} // getTime
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a string representation of the beacon.
|
||||
* @return The string representation.
|
||||
*/
|
||||
std::string NimBLEEddystoneTLM::toString() {
|
||||
std::string out = "";
|
||||
uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||
char val[12];
|
||||
|
||||
out += "Version "; // + std::string(m_eddystoneData.version);
|
||||
snprintf(val, sizeof(val), "%d", m_eddystoneData.version);
|
||||
out += val;
|
||||
out += "\n";
|
||||
out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt));
|
||||
out += val;
|
||||
out += " mV\n";
|
||||
|
||||
out += "Temperature ";
|
||||
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
|
||||
out += val;
|
||||
out += " C\n";
|
||||
|
||||
out += "Adv. Count ";
|
||||
snprintf(val, sizeof(val), "%" PRIu32, ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
out += "Time in seconds ";
|
||||
snprintf(val, sizeof(val), "%" PRIu32, rawsec/10);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
out += "Time ";
|
||||
|
||||
snprintf(val, sizeof(val), "%04" PRIu32, rawsec / 864000);
|
||||
out += val;
|
||||
out += ".";
|
||||
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 36000) % 24);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 600) % 60);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
snprintf(val, sizeof(val), "%02" PRIu32, (rawsec / 10) % 60);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
return out;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the beacon advertisment.
|
||||
* @param [in] data The raw data to advertise.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setData(const std::string &data) {
|
||||
if (data.length() != sizeof(m_eddystoneData)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d",
|
||||
data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_eddystoneData, data.data(), data.length());
|
||||
} // setData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the UUID to advertise.
|
||||
* @param [in] l_uuid The UUID.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setUUID(const NimBLEUUID &l_uuid) {
|
||||
beaconUUID = l_uuid.getNative()->u16.value;
|
||||
} // setUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the version to advertise.
|
||||
* @param [in] version The version number.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setVersion(uint8_t version) {
|
||||
m_eddystoneData.version = version;
|
||||
} // setVersion
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the battery voltage to advertise.
|
||||
* @param [in] volt The voltage in millivolts.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setVolt(uint16_t volt) {
|
||||
m_eddystoneData.volt = volt;
|
||||
} // setVolt
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the temperature to advertise.
|
||||
* @param [in] temp The temperature value.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setTemp(float temp) {
|
||||
m_eddystoneData.temp = (uint16_t)temp;
|
||||
} // setTemp
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisment count.
|
||||
* @param [in] advCount The advertisment number.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setCount(uint32_t advCount) {
|
||||
m_eddystoneData.advCount = advCount;
|
||||
} // setCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisment time.
|
||||
* @param [in] tmil The advertisment time in milliseconds.
|
||||
*/
|
||||
void NimBLEEddystoneTLM::setTime(uint32_t tmil) {
|
||||
m_eddystoneData.tmil = tmil;
|
||||
} // setTime
|
||||
|
||||
#endif
|
||||
61
lib/NimBLE-Arduino/src/NimBLEEddystoneTLM.h
Normal file
61
lib/NimBLE-Arduino/src/NimBLEEddystoneTLM.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* NimBLEEddystoneTLM.h
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEEddystoneTLM.h
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
|
||||
#ifndef _NimBLEEddystoneTLM_H_
|
||||
#define _NimBLEEddystoneTLM_H_
|
||||
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define EDDYSTONE_TLM_FRAME_TYPE 0x20
|
||||
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://github.com/google/eddystone
|
||||
*/
|
||||
class NimBLEEddystoneTLM {
|
||||
public:
|
||||
NimBLEEddystoneTLM();
|
||||
std::string getData();
|
||||
NimBLEUUID getUUID();
|
||||
uint8_t getVersion();
|
||||
uint16_t getVolt();
|
||||
float getTemp();
|
||||
uint32_t getCount();
|
||||
uint32_t getTime();
|
||||
std::string toString();
|
||||
void setData(const std::string &data);
|
||||
void setUUID(const NimBLEUUID &l_uuid);
|
||||
void setVersion(uint8_t version);
|
||||
void setVolt(uint16_t volt);
|
||||
void setTemp(float temp);
|
||||
void setCount(uint32_t advCount);
|
||||
void setTime(uint32_t tmil);
|
||||
|
||||
private:
|
||||
uint16_t beaconUUID;
|
||||
struct {
|
||||
uint8_t frameType;
|
||||
uint8_t version;
|
||||
uint16_t volt;
|
||||
uint16_t temp;
|
||||
uint32_t advCount;
|
||||
uint32_t tmil;
|
||||
} __attribute__((packed)) m_eddystoneData;
|
||||
|
||||
}; // NimBLEEddystoneTLM
|
||||
|
||||
#endif /* _NimBLEEddystoneTLM_H_ */
|
||||
204
lib/NimBLE-Arduino/src/NimBLEEddystoneURL.cpp
Normal file
204
lib/NimBLE-Arduino/src/NimBLEEddystoneURL.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* NimBLEEddystoneURL.cpp
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEEddystoneURL.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEEddystoneURL.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static const char LOG_TAG[] = "NimBLEEddystoneURL";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a default EddystoneURL beacon object.
|
||||
*/
|
||||
NimBLEEddystoneURL::NimBLEEddystoneURL() {
|
||||
beaconUUID = 0xFEAA;
|
||||
lengthURL = 0;
|
||||
m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE;
|
||||
m_eddystoneData.advertisedTxPower = 0;
|
||||
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
|
||||
} // BLEEddystoneURL
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the data that is being advertised.
|
||||
* @return The advertised data.
|
||||
*/
|
||||
std::string NimBLEEddystoneURL::getData() {
|
||||
return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
|
||||
} // getData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID being advertised.
|
||||
* @return The UUID advertised.
|
||||
*/
|
||||
NimBLEUUID NimBLEEddystoneURL::getUUID() {
|
||||
return NimBLEUUID(beaconUUID);
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the transmit power being advertised.
|
||||
* @return The transmit power.
|
||||
*/
|
||||
int8_t NimBLEEddystoneURL::getPower() {
|
||||
return m_eddystoneData.advertisedTxPower;
|
||||
} // getPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the raw URL being advertised.
|
||||
* @return The raw URL.
|
||||
*/
|
||||
std::string NimBLEEddystoneURL::getURL() {
|
||||
return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url));
|
||||
} // getURL
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the full URL being advertised.
|
||||
* @return The full URL.
|
||||
*/
|
||||
std::string NimBLEEddystoneURL::getDecodedURL() {
|
||||
std::string decodedURL = "";
|
||||
|
||||
switch (m_eddystoneData.url[0]) {
|
||||
case 0x00:
|
||||
decodedURL += "http://www.";
|
||||
break;
|
||||
case 0x01:
|
||||
decodedURL += "https://www.";
|
||||
break;
|
||||
case 0x02:
|
||||
decodedURL += "http://";
|
||||
break;
|
||||
case 0x03:
|
||||
decodedURL += "https://";
|
||||
break;
|
||||
default:
|
||||
decodedURL += m_eddystoneData.url[0];
|
||||
}
|
||||
|
||||
for (int i = 1; i < lengthURL; i++) {
|
||||
if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) {
|
||||
decodedURL += m_eddystoneData.url[i];
|
||||
} else {
|
||||
switch (m_eddystoneData.url[i]) {
|
||||
case 0x00:
|
||||
decodedURL += ".com/";
|
||||
break;
|
||||
case 0x01:
|
||||
decodedURL += ".org/";
|
||||
break;
|
||||
case 0x02:
|
||||
decodedURL += ".edu/";
|
||||
break;
|
||||
case 0x03:
|
||||
decodedURL += ".net/";
|
||||
break;
|
||||
case 0x04:
|
||||
decodedURL += ".info/";
|
||||
break;
|
||||
case 0x05:
|
||||
decodedURL += ".biz/";
|
||||
break;
|
||||
case 0x06:
|
||||
decodedURL += ".gov/";
|
||||
break;
|
||||
case 0x07:
|
||||
decodedURL += ".com";
|
||||
break;
|
||||
case 0x08:
|
||||
decodedURL += ".org";
|
||||
break;
|
||||
case 0x09:
|
||||
decodedURL += ".edu";
|
||||
break;
|
||||
case 0x0A:
|
||||
decodedURL += ".net";
|
||||
break;
|
||||
case 0x0B:
|
||||
decodedURL += ".info";
|
||||
break;
|
||||
case 0x0C:
|
||||
decodedURL += ".biz";
|
||||
break;
|
||||
case 0x0D:
|
||||
decodedURL += ".gov";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return decodedURL;
|
||||
} // getDecodedURL
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the raw data for the beacon advertisment.
|
||||
* @param [in] data The raw data to advertise.
|
||||
*/
|
||||
void NimBLEEddystoneURL::setData(const std::string &data) {
|
||||
if (data.length() > sizeof(m_eddystoneData)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d",
|
||||
data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memset(&m_eddystoneData, 0, sizeof(m_eddystoneData));
|
||||
memcpy(&m_eddystoneData, data.data(), data.length());
|
||||
lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url));
|
||||
} // setData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the UUID to advertise.
|
||||
* @param [in] l_uuid The UUID.
|
||||
*/
|
||||
void NimBLEEddystoneURL::setUUID(const NimBLEUUID &l_uuid) {
|
||||
beaconUUID = l_uuid.getNative()->u16.value;
|
||||
} // setUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the transmit power to advertise.
|
||||
* @param [in] advertisedTxPower The transmit power level.
|
||||
*/
|
||||
void NimBLEEddystoneURL::setPower(int8_t advertisedTxPower) {
|
||||
m_eddystoneData.advertisedTxPower = advertisedTxPower;
|
||||
} // setPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the URL to advertise.
|
||||
* @param [in] url The URL.
|
||||
*/
|
||||
void NimBLEEddystoneURL::setURL(const std::string &url) {
|
||||
if (url.length() > sizeof(m_eddystoneData.url)) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d",
|
||||
url.length(), sizeof(m_eddystoneData.url));
|
||||
return;
|
||||
}
|
||||
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
|
||||
memcpy(m_eddystoneData.url, url.data(), url.length());
|
||||
lengthURL = url.length();
|
||||
} // setURL
|
||||
|
||||
|
||||
#endif
|
||||
52
lib/NimBLE-Arduino/src/NimBLEEddystoneURL.h
Normal file
52
lib/NimBLE-Arduino/src/NimBLEEddystoneURL.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* NimBLEEddystoneURL.h
|
||||
*
|
||||
* Created: on March 15 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEEddystoneURL.h
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
|
||||
#ifndef _NIMBLEEddystoneURL_H_
|
||||
#define _NIMBLEEddystoneURL_H_
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define EDDYSTONE_URL_FRAME_TYPE 0x10
|
||||
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://github.com/google/eddystone
|
||||
*/
|
||||
class NimBLEEddystoneURL {
|
||||
public:
|
||||
NimBLEEddystoneURL();
|
||||
std::string getData();
|
||||
NimBLEUUID getUUID();
|
||||
int8_t getPower();
|
||||
std::string getURL();
|
||||
std::string getDecodedURL();
|
||||
void setData(const std::string &data);
|
||||
void setUUID(const NimBLEUUID &l_uuid);
|
||||
void setPower(int8_t advertisedTxPower);
|
||||
void setURL(const std::string &url);
|
||||
|
||||
private:
|
||||
uint16_t beaconUUID;
|
||||
uint8_t lengthURL;
|
||||
struct {
|
||||
uint8_t frameType;
|
||||
int8_t advertisedTxPower;
|
||||
uint8_t url[16];
|
||||
} __attribute__((packed)) m_eddystoneData;
|
||||
|
||||
}; // NIMBLEEddystoneURL
|
||||
|
||||
#endif /* _NIMBLEEddystoneURL_H_ */
|
||||
248
lib/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
Normal file
248
lib/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* NimBLEHIDDevice.cpp
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.cpp
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEHIDDevice.h"
|
||||
#include "NimBLE2904.h"
|
||||
|
||||
/**
|
||||
* @brief Construct a default NimBLEHIDDevice object.
|
||||
* @param [in] server A pointer to the server instance this HID Device will use.
|
||||
*/
|
||||
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
*/
|
||||
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
|
||||
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812));
|
||||
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service
|
||||
*/
|
||||
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristics for HID service
|
||||
*/
|
||||
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ);
|
||||
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ);
|
||||
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
|
||||
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);
|
||||
|
||||
/*
|
||||
* Mandatory battery level characteristic with notification and presence descriptor
|
||||
*/
|
||||
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
|
||||
NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904);
|
||||
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
/*
|
||||
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
|
||||
* and we want to simplify library using as much as possible
|
||||
*/
|
||||
const uint8_t pMode[] = { 0x01 };
|
||||
protocolMode()->setValue((uint8_t*) pMode, 1);
|
||||
}
|
||||
|
||||
NimBLEHIDDevice::~NimBLEHIDDevice() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the report map data formatting information.
|
||||
* @param [in] map A pointer to an array with the values to set.
|
||||
* @param [in] size The number of values in the array.
|
||||
*/
|
||||
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the HID device services.\n
|
||||
* This function called when all the services have been created.
|
||||
*/
|
||||
void NimBLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
m_hidService->start();
|
||||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a manufacturer characteristic (this characteristic is optional).
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name The manufacturer name of this HID device.
|
||||
*/
|
||||
void NimBLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the Plug n Play characterisc value.
|
||||
* @param [in] sig The vendor ID source number.
|
||||
* @param [in] vid The vendor ID number.
|
||||
* @param [in] pid The product ID number.
|
||||
* @param [in] version The produce version number.
|
||||
*/
|
||||
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the HID Information characteristic value.
|
||||
* @param [in] country The country code for the device.
|
||||
* @param [in] flags The HID Class Specification release number to use.
|
||||
*/
|
||||
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create input report characteristic
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
|
||||
NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x01 };
|
||||
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create output report characteristic
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x02 };
|
||||
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create feature report characteristic.
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x03 };
|
||||
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
|
||||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a keyboard boot input report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a keyboard boot output report characteristic
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID control point characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the protocol mode characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the battery level characteristic value.
|
||||
* @param [in] level The battery level value.
|
||||
*/
|
||||
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
}
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::pnp() {
|
||||
return m_pnpCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::hidInfo() {
|
||||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the device information service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the HID service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief @brief Returns a pointer to the battery service.
|
||||
*/
|
||||
NimBLEService* NimBLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
86
lib/NimBLE-Arduino/src/NimBLEHIDDevice.h
Normal file
86
lib/NimBLE-Arduino/src/NimBLEHIDDevice.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* NimBLEHIDDevice.h
|
||||
*
|
||||
* Created: on Oct 06 2020
|
||||
* Author wakwak-koba
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEHIDDevice.h
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef _BLEHIDDEVICE_H_
|
||||
#define _BLEHIDDEVICE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
|
||||
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEDescriptor.h"
|
||||
#include "HIDTypes.h"
|
||||
|
||||
#define GENERIC_HID 0x03C0
|
||||
#define HID_KEYBOARD 0x03C1
|
||||
#define HID_MOUSE 0x03C2
|
||||
#define HID_JOYSTICK 0x03C3
|
||||
#define HID_GAMEPAD 0x03C4
|
||||
#define HID_TABLET 0x03C5
|
||||
#define HID_CARD_READER 0x03C6
|
||||
#define HID_DIGITAL_PEN 0x03C7
|
||||
#define HID_BARCODE 0x03C8
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE Human Interface Device.
|
||||
*/
|
||||
class NimBLEHIDDevice {
|
||||
public:
|
||||
NimBLEHIDDevice(NimBLEServer*);
|
||||
virtual ~NimBLEHIDDevice();
|
||||
|
||||
void reportMap(uint8_t* map, uint16_t);
|
||||
void startServices();
|
||||
|
||||
NimBLEService* deviceInfo();
|
||||
NimBLEService* hidService();
|
||||
NimBLEService* batteryService();
|
||||
|
||||
NimBLECharacteristic* manufacturer();
|
||||
void manufacturer(std::string name);
|
||||
//NimBLECharacteristic* pnp();
|
||||
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
//NimBLECharacteristic* hidInfo();
|
||||
void hidInfo(uint8_t country, uint8_t flags);
|
||||
//NimBLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
//NimBLECharacteristic* reportMap();
|
||||
NimBLECharacteristic* hidControl();
|
||||
NimBLECharacteristic* inputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* outputReport(uint8_t reportID);
|
||||
NimBLECharacteristic* featureReport(uint8_t reportID);
|
||||
NimBLECharacteristic* protocolMode();
|
||||
NimBLECharacteristic* bootInput();
|
||||
NimBLECharacteristic* bootOutput();
|
||||
|
||||
private:
|
||||
NimBLEService* m_deviceInfoService; //0x180a
|
||||
NimBLEService* m_hidService; //0x1812
|
||||
NimBLEService* m_batteryService = 0; //0x180f
|
||||
|
||||
NimBLECharacteristic* m_manufacturerCharacteristic; //0x2a29
|
||||
NimBLECharacteristic* m_pnpCharacteristic; //0x2a50
|
||||
NimBLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
|
||||
NimBLECharacteristic* m_reportMapCharacteristic; //0x2a4b
|
||||
NimBLECharacteristic* m_hidControlCharacteristic; //0x2a4c
|
||||
NimBLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||
NimBLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER */
|
||||
#endif /* _BLEHIDDEVICE_H_ */
|
||||
80
lib/NimBLE-Arduino/src/NimBLELog.h
Normal file
80
lib/NimBLE-Arduino/src/NimBLELog.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* NimBLELog.h
|
||||
*
|
||||
* Created: on Feb 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
#ifndef MAIN_NIMBLELOG_H_
|
||||
#define MAIN_NIMBLELOG_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
|
||||
# include "esp_log.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
|
||||
# define NIMBLE_CPP_LOG_PRINT(level, tag, format, ...) do { \
|
||||
if (CONFIG_NIMBLE_CPP_LOG_LEVEL >= level) \
|
||||
ESP_LOG_LEVEL_LOCAL(level, tag, format, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
# define NIMBLE_LOGD(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_DEBUG, tag, format, ##__VA_ARGS__)
|
||||
|
||||
# define NIMBLE_LOGI(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_INFO, tag, format, ##__VA_ARGS__)
|
||||
|
||||
# define NIMBLE_LOGW(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_WARN, tag, format, ##__VA_ARGS__)
|
||||
|
||||
# define NIMBLE_LOGE(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
# define NIMBLE_LOGC(tag, format, ...) \
|
||||
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#else // using Arduino
|
||||
# include "nimble/porting/nimble/include/syscfg/syscfg.h"
|
||||
# include "nimble/console/console.h"
|
||||
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
|
||||
# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL
|
||||
# else
|
||||
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
# define NIMBLE_LOGD( tag, format, ... ) console_printf("D %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGD( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 3
|
||||
# define NIMBLE_LOGI( tag, format, ... ) console_printf("I %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGI( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 2
|
||||
# define NIMBLE_LOGW( tag, format, ... ) console_printf("W %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGW( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 1
|
||||
# define NIMBLE_LOGE( tag, format, ... ) console_printf("E %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# define NIMBLE_LOGC( tag, format, ... ) console_printf("CRIT %s: " format "\n", tag, ##__VA_ARGS__)
|
||||
# else
|
||||
# define NIMBLE_LOGE( tag, format, ... ) (void)tag
|
||||
# define NIMBLE_LOGC( tag, format, ... ) (void)tag
|
||||
# endif
|
||||
|
||||
#endif /* CONFIG_NIMBLE_CPP_IDF */
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* MAIN_NIMBLELOG_H_ */
|
||||
865
lib/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp
Normal file
865
lib/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp
Normal file
@@ -0,0 +1,865 @@
|
||||
/*
|
||||
* NimBLERemoteCharacteristic.cpp
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteCharacteristic.cpp
|
||||
*
|
||||
* Created on: Mar 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteCharacteristic";
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param [in] reference to the service this characteristic belongs to.
|
||||
* @param [in] ble_gatt_chr struct defined as:
|
||||
* struct ble_gatt_chr {
|
||||
* uint16_t def_handle;
|
||||
* uint16_t val_handle;
|
||||
* uint8_t properties;
|
||||
* ble_uuid_any_t uuid;
|
||||
* };
|
||||
*/
|
||||
NimBLERemoteCharacteristic::NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteService,
|
||||
const struct ble_gatt_chr *chr)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteCharacteristic()");
|
||||
switch (chr->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(chr->uuid.u16.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_32:
|
||||
m_uuid = NimBLEUUID(chr->uuid.u32.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_128:
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&chr->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_handle = chr->val_handle;
|
||||
m_defHandle = chr->def_handle;
|
||||
m_endHandle = 0;
|
||||
m_charProp = chr->properties;
|
||||
m_pRemoteService = pRemoteService;
|
||||
m_notifyCallback = nullptr;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteCharacteristic(): %s", m_uuid.toString().c_str());
|
||||
} // NimBLERemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
*@brief Destructor.
|
||||
*/
|
||||
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
|
||||
deleteDescriptors();
|
||||
} // ~NimBLERemoteCharacteristic
|
||||
|
||||
/*
|
||||
#define BLE_GATT_CHR_PROP_BROADCAST 0x01
|
||||
#define BLE_GATT_CHR_PROP_READ 0x02
|
||||
#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04
|
||||
#define BLE_GATT_CHR_PROP_WRITE 0x08
|
||||
#define BLE_GATT_CHR_PROP_NOTIFY 0x10
|
||||
#define BLE_GATT_CHR_PROP_INDICATE 0x20
|
||||
#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40
|
||||
#define BLE_GATT_CHR_PROP_EXTENDED 0x80
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support broadcasting?
|
||||
* @return True if the characteristic supports broadcasting.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canBroadcast() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_BROADCAST) != 0;
|
||||
} // canBroadcast
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support indications?
|
||||
* @return True if the characteristic supports indications.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canIndicate() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_INDICATE) != 0;
|
||||
} // canIndicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support notifications?
|
||||
* @return True if the characteristic supports notifications.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canNotify() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_NOTIFY) != 0;
|
||||
} // canNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support reading?
|
||||
* @return True if the characteristic supports reading.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canRead() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_READ) != 0;
|
||||
} // canRead
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support writing?
|
||||
* @return True if the characteristic supports writing.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canWrite() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_WRITE) != 0;
|
||||
} // canWrite
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support writing with no response?
|
||||
* @return True if the characteristic supports writing with no response.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::canWriteNoResponse() {
|
||||
return (m_charProp & BLE_GATT_CHR_PROP_WRITE_NO_RSP) != 0;
|
||||
} // canWriteNoResponse
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback used by the API when a descriptor is discovered or search complete.
|
||||
*/
|
||||
int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg)
|
||||
{
|
||||
int rc = error->status;
|
||||
NIMBLE_LOGD(LOG_TAG, "Descriptor Discovered >> status: %d handle: %d",
|
||||
rc, (rc == 0) ? dsc->handle : -1);
|
||||
|
||||
desc_filter_t *filter = (desc_filter_t*)arg;
|
||||
const NimBLEUUID *uuid_filter = filter->uuid;
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
|
||||
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
|
||||
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
case 0: {
|
||||
if (uuid_filter != nullptr) {
|
||||
if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
|
||||
return 0;
|
||||
} else {
|
||||
rc = BLE_HS_EDONE;
|
||||
}
|
||||
}
|
||||
|
||||
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
|
||||
characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
|
||||
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
|
||||
* If we get any other error code tell the application to abort by returning non-zero in the rc.
|
||||
*/
|
||||
if (rc == BLE_HS_EDONE) {
|
||||
pTaskData->rc = 0;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
} else if(rc != 0) {
|
||||
// Error; abort discovery.
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief callback from NimBLE when the next characteristic of the service is discovered.
|
||||
*/
|
||||
int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg)
|
||||
{
|
||||
int rc = error->status;
|
||||
NIMBLE_LOGD(LOG_TAG, "Next Characteristic >> status: %d handle: %d",
|
||||
rc, (rc == 0) ? chr->val_handle : -1);
|
||||
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteCharacteristic *pChar = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
|
||||
if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
pChar->m_endHandle = chr->def_handle - 1;
|
||||
rc = BLE_HS_EDONE;
|
||||
} else if (rc == BLE_HS_EDONE) {
|
||||
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
|
||||
} else {
|
||||
pTaskData->rc = rc;
|
||||
}
|
||||
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Populate the descriptors (if any) for this characteristic.
|
||||
* @param [in] the end handle of the characteristic, or the service, whichever comes first.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
|
||||
|
||||
// If this is the last handle then there are no descriptors
|
||||
if (m_handle == getRemoteService()->getEndHandle()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
// If we don't know the end handle of this characteristic retrieve the next one in the service
|
||||
// The end handle is the next characteristic definition handle -1.
|
||||
if (m_endHandle == 0) {
|
||||
rc = ble_gattc_disc_all_chrs(getRemoteService()->getClient()->getConnId(),
|
||||
m_handle,
|
||||
getRemoteService()->getEndHandle(),
|
||||
NimBLERemoteCharacteristic::nextCharCB,
|
||||
&taskData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error getting end handle rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_handle == m_endHandle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
desc_filter_t filter = {uuid_filter, &taskData};
|
||||
|
||||
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
|
||||
m_handle,
|
||||
m_endHandle,
|
||||
NimBLERemoteCharacteristic::descriptorDiscCB,
|
||||
&filter);
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_dscs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if (taskData.rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
|
||||
m_handle, m_endHandle, taskData.rc);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
|
||||
return (taskData.rc == 0);
|
||||
} // retrieveDescriptors
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the descriptor instance with the given UUID that belongs to this characteristic.
|
||||
* @param [in] uuid The UUID of the descriptor to find.
|
||||
* @return The Remote descriptor (if present) or null if not present.
|
||||
*/
|
||||
NimBLERemoteDescriptor* NimBLERemoteCharacteristic::getDescriptor(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
|
||||
|
||||
for(auto &it: m_descriptorVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: found the descriptor with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
size_t prev_size = m_descriptorVector.size();
|
||||
if(retrieveDescriptors(&uuid)) {
|
||||
if(m_descriptorVector.size() > prev_size) {
|
||||
return m_descriptorVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit uuid not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
if(retrieveDescriptors(&uuid128)) {
|
||||
if(m_descriptorVector.size() > prev_size) {
|
||||
return m_descriptorVector.back();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the request was successful but the 128 bit uuid not found
|
||||
// try again with the 16 bit uuid.
|
||||
NimBLEUUID uuid16(uuid);
|
||||
uuid16.to16();
|
||||
// if the uuid was 128 bit but not of the BLE base type this check will fail
|
||||
if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
|
||||
if(retrieveDescriptors(&uuid16)) {
|
||||
if(m_descriptorVector.size() > prev_size) {
|
||||
return m_descriptorVector.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getDescriptor: Not found");
|
||||
return nullptr;
|
||||
} // getDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the vector of found descriptors.
|
||||
* @param [in] refresh If true the current descriptor vector will be cleared and\n
|
||||
* all descriptors for this characteristic retrieved from the peripheral.\n
|
||||
* If false the vector will be returned with the currently stored descriptors
|
||||
* of this characteristic.
|
||||
* @return A pointer to the vector of descriptors for this characteristic.
|
||||
*/
|
||||
std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors(bool refresh) {
|
||||
if(refresh) {
|
||||
deleteDescriptors();
|
||||
|
||||
if (!retrieveDescriptors()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get descriptors");
|
||||
}
|
||||
else{
|
||||
NIMBLE_LOGI(LOG_TAG, "Found %d descriptor(s)", m_descriptorVector.size());
|
||||
}
|
||||
}
|
||||
return &m_descriptorVector;
|
||||
} // getDescriptors
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the beginning of the vector of remote descriptor pointers.
|
||||
* @return An iterator to the beginning of the vector of remote descriptor pointers.
|
||||
*/
|
||||
std::vector<NimBLERemoteDescriptor*>::iterator NimBLERemoteCharacteristic::begin() {
|
||||
return m_descriptorVector.begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the end of the vector of remote descriptor pointers.
|
||||
* @return An iterator to the end of the vector of remote descriptor pointers.
|
||||
*/
|
||||
std::vector<NimBLERemoteDescriptor*>::iterator NimBLERemoteCharacteristic::end() {
|
||||
return m_descriptorVector.end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle for this characteristic.
|
||||
* @return The handle for this characteristic.
|
||||
*/
|
||||
uint16_t NimBLERemoteCharacteristic::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
/**
|
||||
* @brief Get the handle for this characteristics definition.
|
||||
* @return The handle for this characteristic definition.
|
||||
*/
|
||||
uint16_t NimBLERemoteCharacteristic::getDefHandle() {
|
||||
return m_defHandle;
|
||||
} // getDefHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote service associated with this characteristic.
|
||||
* @return The remote service associated with this characteristic.
|
||||
*/
|
||||
NimBLERemoteService* NimBLERemoteCharacteristic::getRemoteService() {
|
||||
return m_pRemoteService;
|
||||
} // getRemoteService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID for this characteristic.
|
||||
* @return The UUID for this characteristic.
|
||||
*/
|
||||
NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of the remote characteristic.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = m_value.getTimeStamp();
|
||||
}
|
||||
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 16 bit value
|
||||
* @return The unsigned 16 bit value.
|
||||
* @deprecated Use readValue<uint16_t>().
|
||||
*/
|
||||
uint16_t NimBLERemoteCharacteristic::readUInt16() {
|
||||
return readValue<uint16_t>();
|
||||
} // readUInt16
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 32 bit value.
|
||||
* @return the unsigned 32 bit value.
|
||||
* @deprecated Use readValue<uint32_t>().
|
||||
*/
|
||||
uint32_t NimBLERemoteCharacteristic::readUInt32() {
|
||||
return readValue<uint32_t>();
|
||||
} // readUInt32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a byte value
|
||||
* @return The value as a byte
|
||||
* @deprecated Use readValue<uint8_t>().
|
||||
*/
|
||||
uint8_t NimBLERemoteCharacteristic::readUInt8() {
|
||||
return readValue<uint8_t>();
|
||||
} // readUInt8
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a float value.
|
||||
* @return the float value.
|
||||
*/
|
||||
float NimBLERemoteCharacteristic::readFloat() {
|
||||
return readValue<float>();
|
||||
} // readFloat
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read the value of the remote characteristic.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
|
||||
getUUID().toString().c_str(), getHandle(), getHandle());
|
||||
|
||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||
NimBLEAttValue value;
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
return value;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||
|
||||
do {
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
NimBLERemoteCharacteristic::onReadCB,
|
||||
&taskData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
case 0:
|
||||
case BLE_HS_EDONE:
|
||||
rc = 0;
|
||||
break;
|
||||
// Characteristic is not long-readable, return with what we have.
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
||||
rc = 0;
|
||||
break;
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||
if (retryCount && pClient->secureConnection())
|
||||
break;
|
||||
/* Else falls through. */
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc);
|
||||
return value;
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
value.setTimeStamp();
|
||||
m_value = value;
|
||||
if(timestamp != nullptr) {
|
||||
*timestamp = value.getTimeStamp();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
|
||||
return value;
|
||||
} // readValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for characteristic read operation.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg)
|
||||
{
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
|
||||
|
||||
if(conn_id != conn_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||
int rc = error->status;
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||
valBuf->append(attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Subscribe or unsubscribe for notifications or indications.
|
||||
* @param [in] val 0x00 to unsubscribe, 0x01 for notifications, 0x02 for indications.
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If write response required set this to true.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val);
|
||||
|
||||
m_notifyCallback = notifyCallback;
|
||||
|
||||
NimBLERemoteDescriptor* desc = getDescriptor(NimBLEUUID((uint16_t)0x2902));
|
||||
if(desc == nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "<< setNotify(): Callback set, CCCD not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
|
||||
|
||||
return desc->writeValue((uint8_t *)&val, 2, response);
|
||||
} // setNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Subscribe for notifications or indications.
|
||||
* @param [in] notifications If true, subscribe for notifications, false subscribe for indications.
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification.
|
||||
* @param [in] response If true, require a write response from the descriptor write operation.
|
||||
* If NULL is provided then no callback is performed.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) {
|
||||
if(notifications) {
|
||||
return setNotify(0x01, notifyCallback, response);
|
||||
} else {
|
||||
return setNotify(0x02, notifyCallback, response);
|
||||
}
|
||||
} // subscribe
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe for notifications or indications.
|
||||
* @param [in] response bool if true, require a write response from the descriptor write operation.
|
||||
* @return false if writing to the descriptor failed.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::unsubscribe(bool response) {
|
||||
return setNotify(0x00, nullptr, response);
|
||||
} // unsubscribe
|
||||
|
||||
|
||||
/**
|
||||
* @brief backward-compatibility method for subscribe/unsubscribe notifications/indications
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we
|
||||
* will unregister for notifications.
|
||||
* @param [in] notifications If true, register for notifications, false register for indications.
|
||||
* @param [in] response If true, require a write response from the descriptor write operation.
|
||||
* @return true if successful.
|
||||
* @deprecated Use subscribe() / unsubscribe() instead.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool response) {
|
||||
bool success;
|
||||
if(notifyCallback != nullptr) {
|
||||
success = subscribe(notifications, notifyCallback, response);
|
||||
} else {
|
||||
success = unsubscribe(response);
|
||||
}
|
||||
return success;
|
||||
} // registerForNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the descriptors in the descriptor vector.
|
||||
* @details We maintain a vector called m_descriptorVector that contains pointers to NimBLERemoteDescriptors
|
||||
* object references. Since we allocated these in this class, we are also responsible for deleting
|
||||
* them. This method does just that.
|
||||
*/
|
||||
void NimBLERemoteCharacteristic::deleteDescriptors() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors");
|
||||
|
||||
for(auto &it: m_descriptorVector) {
|
||||
delete it;
|
||||
}
|
||||
m_descriptorVector.clear();
|
||||
NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptors");
|
||||
} // deleteDescriptors
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete descriptor by UUID
|
||||
* @param [in] uuid The UUID of the descriptor to be deleted.
|
||||
* @return Number of descriptors left in the vector.
|
||||
*/
|
||||
size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor");
|
||||
|
||||
for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) {
|
||||
if((*it)->getUUID() == uuid) {
|
||||
delete *it;
|
||||
m_descriptorVector.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< deleteDescriptor");
|
||||
|
||||
return m_descriptorVector.size();
|
||||
} // deleteDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a NimBLERemoteCharacteristic to a string representation;
|
||||
* @return a String representation.
|
||||
*/
|
||||
std::string NimBLERemoteCharacteristic::toString() {
|
||||
std::string res = "Characteristic: uuid: " + m_uuid.toString();
|
||||
char val[6];
|
||||
res += ", handle: ";
|
||||
snprintf(val, sizeof(val), "%d", getHandle());
|
||||
res += val;
|
||||
res += " 0x";
|
||||
snprintf(val, sizeof(val), "%04x", getHandle());
|
||||
res += val;
|
||||
res += ", props: ";
|
||||
res += " 0x";
|
||||
snprintf(val, sizeof(val), "%02x", m_charProp);
|
||||
res += val;
|
||||
|
||||
for(auto &it: m_descriptorVector) {
|
||||
res += "\n" + it->toString();
|
||||
}
|
||||
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a std::vector<uint8_t>.
|
||||
* @param [in] vec A std::vector<uint8_t> value to write to the remote characteristic.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a const char*.
|
||||
* @param [in] char_s A character string to write to the remote characteristic.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const char* char_s, bool response) {
|
||||
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote characteristic from a data buffer.
|
||||
* @param [in] data A pointer to a data buffer.
|
||||
* @param [in] length The length of the data in the data buffer.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length);
|
||||
|
||||
NimBLEClient* pClient = getRemoteService()->getClient();
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||
|
||||
// Check if the data length is longer than we can write in one connection event.
|
||||
// If so we must do a long write which requires a response.
|
||||
if(length <= mtu && !response) {
|
||||
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
||||
return (rc==0);
|
||||
}
|
||||
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
do {
|
||||
if(length > mtu) {
|
||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
|
||||
NimBLERemoteCharacteristic::onWriteCB,
|
||||
&taskData);
|
||||
} else {
|
||||
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
||||
data, length,
|
||||
NimBLERemoteCharacteristic::onWriteCB,
|
||||
&taskData);
|
||||
}
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
case 0:
|
||||
case BLE_HS_EDONE:
|
||||
rc = 0;
|
||||
break;
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
|
||||
retryCount++;
|
||||
length = mtu;
|
||||
break;
|
||||
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||
if (retryCount && pClient->secureConnection())
|
||||
break;
|
||||
/* Else falls through. */
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc);
|
||||
return false;
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc);
|
||||
return (rc == 0);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for characteristic write operation.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg)
|
||||
{
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
|
||||
|
||||
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
pTaskData->rc = error->status;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
190
lib/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h
Normal file
190
lib/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* NimBLERemoteCharacteristic.h
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteCharacteristic.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||
#define COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteService.h"
|
||||
#include "NimBLERemoteDescriptor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "NimBLELog.h"
|
||||
|
||||
class NimBLERemoteService;
|
||||
class NimBLERemoteDescriptor;
|
||||
|
||||
|
||||
typedef std::function<void (NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||
uint8_t* pData, size_t length, bool isNotify)> notify_callback;
|
||||
|
||||
typedef struct {
|
||||
const NimBLEUUID *uuid;
|
||||
void *task_data;
|
||||
} desc_filter_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a remote %BLE characteristic.
|
||||
*/
|
||||
class NimBLERemoteCharacteristic {
|
||||
public:
|
||||
~NimBLERemoteCharacteristic();
|
||||
|
||||
// Public member functions
|
||||
bool canBroadcast();
|
||||
bool canIndicate();
|
||||
bool canNotify();
|
||||
bool canRead();
|
||||
bool canWrite();
|
||||
bool canWriteNoResponse();
|
||||
std::vector<NimBLERemoteDescriptor*>::iterator begin();
|
||||
std::vector<NimBLERemoteDescriptor*>::iterator end();
|
||||
NimBLERemoteDescriptor* getDescriptor(const NimBLEUUID &uuid);
|
||||
std::vector<NimBLERemoteDescriptor*>* getDescriptors(bool refresh = false);
|
||||
void deleteDescriptors();
|
||||
size_t deleteDescriptor(const NimBLEUUID &uuid);
|
||||
uint16_t getHandle();
|
||||
uint16_t getDefHandle();
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEAttValue readValue(time_t *timestamp = nullptr);
|
||||
std::string toString();
|
||||
NimBLERemoteService* getRemoteService();
|
||||
|
||||
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||
float readFloat() __attribute__ ((deprecated("Use template readValue<float>()")));
|
||||
NimBLEAttValue getValue(time_t *timestamp = nullptr);
|
||||
|
||||
bool subscribe(bool notifications = true,
|
||||
notify_callback notifyCallback = nullptr,
|
||||
bool response = false);
|
||||
bool unsubscribe(bool response = false);
|
||||
bool registerForNotify(notify_callback notifyCallback,
|
||||
bool notifications = true,
|
||||
bool response = true)
|
||||
__attribute__ ((deprecated("Use subscribe()/unsubscribe()")));
|
||||
bool writeValue(const uint8_t* data,
|
||||
size_t length,
|
||||
bool response = false);
|
||||
bool writeValue(const std::vector<uint8_t>& v, bool response = false);
|
||||
bool writeValue(const char* s, bool response = false);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote characteristic value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>getValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T getValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
if(!skipSizeCheck && m_value.size() < sizeof(T)) return T();
|
||||
return *((T *)m_value.getValue(timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote characteristic data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>readValue<type>(×tamp, skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T readValue(time_t *timestamp = nullptr, bool skipSizeCheck = false) {
|
||||
NimBLEAttValue value = readValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
return *((T *)value.getValue(timestamp));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NimBLERemoteCharacteristic(NimBLERemoteService *pRemoteservice, const struct ble_gatt_chr *chr);
|
||||
|
||||
friend class NimBLEClient;
|
||||
friend class NimBLERemoteService;
|
||||
friend class NimBLERemoteDescriptor;
|
||||
|
||||
// Private member functions
|
||||
bool setNotify(uint16_t val, notify_callback notifyCallback = nullptr, bool response = true);
|
||||
bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr);
|
||||
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg);
|
||||
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg);
|
||||
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
|
||||
void *arg);
|
||||
static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg);
|
||||
|
||||
// Private properties
|
||||
NimBLEUUID m_uuid;
|
||||
uint8_t m_charProp;
|
||||
uint16_t m_handle;
|
||||
uint16_t m_defHandle;
|
||||
uint16_t m_endHandle;
|
||||
NimBLERemoteService* m_pRemoteService;
|
||||
NimBLEAttValue m_value;
|
||||
notify_callback m_notifyCallback;
|
||||
|
||||
// We maintain a vector of descriptors owned by this characteristic.
|
||||
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;
|
||||
}; // NimBLERemoteCharacteristic
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTECHARACTERISTIC_H_ */
|
||||
365
lib/NimBLE-Arduino/src/NimBLERemoteDescriptor.cpp
Normal file
365
lib/NimBLE-Arduino/src/NimBLERemoteDescriptor.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* NimBLERemoteDescriptor.cpp
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteDescriptor.cpp
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteDescriptor.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteDescriptor";
|
||||
|
||||
/**
|
||||
* @brief Remote descriptor constructor.
|
||||
* @param [in] pRemoteCharacteristic A pointer to the Characteristic that this belongs to.
|
||||
* @param [in] dsc A pointer to the struct that contains the descriptor information.
|
||||
*/
|
||||
NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemoteCharacteristic,
|
||||
const struct ble_gatt_dsc *dsc)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteDescriptor()");
|
||||
switch (dsc->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(dsc->uuid.u16.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_32:
|
||||
m_uuid = NimBLEUUID(dsc->uuid.u32.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_128:
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&dsc->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_handle = dsc->handle;
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteDescriptor(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the handle associated with this remote descriptor.
|
||||
* @return The handle associated with this remote descriptor.
|
||||
*/
|
||||
uint16_t NimBLERemoteDescriptor::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic that owns this descriptor.
|
||||
* @return The characteristic that owns this descriptor.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLERemoteDescriptor::getRemoteCharacteristic() {
|
||||
return m_pRemoteCharacteristic;
|
||||
} // getRemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the UUID associated this remote descriptor.
|
||||
* @return The UUID associated this remote descriptor.
|
||||
*/
|
||||
NimBLEUUID NimBLERemoteDescriptor::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a byte value
|
||||
* @return The value as a byte
|
||||
* @deprecated Use readValue<uint8_t>().
|
||||
*/
|
||||
uint8_t NimBLERemoteDescriptor::readUInt8() {
|
||||
return readValue<uint8_t>();
|
||||
} // readUInt8
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 16 bit value
|
||||
* @return The unsigned 16 bit value.
|
||||
* @deprecated Use readValue<uint16_t>().
|
||||
*/
|
||||
uint16_t NimBLERemoteDescriptor::readUInt16() {
|
||||
return readValue<uint16_t>();
|
||||
} // readUInt16
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 32 bit value.
|
||||
* @return the unsigned 32 bit value.
|
||||
* @deprecated Use readValue<uint32_t>().
|
||||
*/
|
||||
uint32_t NimBLERemoteDescriptor::readUInt32() {
|
||||
return readValue<uint32_t>();
|
||||
} // readUInt32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read the value of the remote descriptor.
|
||||
* @return The value of the remote descriptor.
|
||||
*/
|
||||
NimBLEAttValue NimBLERemoteDescriptor::readValue() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
|
||||
|
||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||
NimBLEAttValue value;
|
||||
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
return value;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, &value};
|
||||
|
||||
do {
|
||||
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
|
||||
NimBLERemoteDescriptor::onReadCB,
|
||||
&taskData);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc){
|
||||
case 0:
|
||||
case BLE_HS_EDONE:
|
||||
rc = 0;
|
||||
break;
|
||||
// Descriptor is not long-readable, return with what we have.
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
|
||||
rc = 0;
|
||||
break;
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||
if (retryCount && pClient->secureConnection())
|
||||
break;
|
||||
/* Else falls through. */
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %u rc=%d", value.length(), rc);
|
||||
return value;
|
||||
} // readValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for Descriptor read operation.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg)
|
||||
{
|
||||
(void)attr;
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
|
||||
|
||||
if(conn_id != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
NimBLEAttValue *valBuf = (NimBLEAttValue*)pTaskData->buf;
|
||||
int rc = error->status;
|
||||
|
||||
if(rc == 0) {
|
||||
if(attr) {
|
||||
uint16_t data_len = OS_MBUF_PKTLEN(attr->om);
|
||||
if((valBuf->size() + data_len) > BLE_ATT_ATTR_MAX_LEN) {
|
||||
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
} else {
|
||||
NIMBLE_LOGD(LOG_TAG, "Got %u bytes", data_len);
|
||||
valBuf->append(attr->om->om_data, data_len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTaskData->rc = rc;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this Remote Descriptor.
|
||||
* @return A string representation of this Remote Descriptor.
|
||||
*/
|
||||
std::string NimBLERemoteDescriptor::toString() {
|
||||
std::string res = "Descriptor: uuid: " + getUUID().toString();
|
||||
char val[6];
|
||||
res += ", handle: ";
|
||||
snprintf(val, sizeof(val), "%d", getHandle());
|
||||
res += val;
|
||||
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for descriptor write operation.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg)
|
||||
{
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT;
|
||||
|
||||
if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
pTaskData->rc = error->status;
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to a remote descriptor from a std::vector<uint8_t>.
|
||||
* @param [in] vec A std::vector<uint8_t> value to write to the remote descriptor.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const std::vector<uint8_t>& vec, bool response) {
|
||||
return writeValue((uint8_t*)&vec[0], vec.size(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to the remote descriptor from a const char*.
|
||||
* @param [in] char_s A character string to write to the remote descriptor.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const char* char_s, bool response) {
|
||||
return writeValue((uint8_t*)char_s, strlen(char_s), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a new value to a remote descriptor.
|
||||
* @param [in] data The data to send to the remote descriptor.
|
||||
* @param [in] length The length of the data to send.
|
||||
* @param [in] response True if we expect a write response.
|
||||
* @return false if not connected or otherwise cannot perform write.
|
||||
*/
|
||||
bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool response) {
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Descriptor writeValue: %s", toString().c_str());
|
||||
|
||||
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!pClient->isConnected()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Disconnected");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
int retryCount = 1;
|
||||
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
|
||||
|
||||
// Check if the data length is longer than we can write in 1 connection event.
|
||||
// If so we must do a long write which requires a response.
|
||||
if(length <= mtu && !response) {
|
||||
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
|
||||
return (rc == 0);
|
||||
}
|
||||
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
do {
|
||||
if(length > mtu) {
|
||||
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
|
||||
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
|
||||
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
|
||||
NimBLERemoteDescriptor::onWriteCB,
|
||||
&taskData);
|
||||
} else {
|
||||
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
|
||||
data, length,
|
||||
NimBLERemoteDescriptor::onWriteCB,
|
||||
&taskData);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
rc = taskData.rc;
|
||||
|
||||
switch(rc) {
|
||||
case 0:
|
||||
case BLE_HS_EDONE:
|
||||
rc = 0;
|
||||
break;
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
|
||||
NIMBLE_LOGE(LOG_TAG, "Long write not supported by peer; Truncating length to %d", mtu);
|
||||
retryCount++;
|
||||
length = mtu;
|
||||
break;
|
||||
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
|
||||
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
|
||||
if (retryCount && pClient->secureConnection())
|
||||
break;
|
||||
/* Else falls through. */
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} while(rc != 0 && retryCount--);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Descriptor writeValue, rc: %d",rc);
|
||||
return (rc == 0);
|
||||
} // writeValue
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
108
lib/NimBLE-Arduino/src/NimBLERemoteDescriptor.h
Normal file
108
lib/NimBLE-Arduino/src/NimBLERemoteDescriptor.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* NimBLERemoteDescriptor.h
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteDescriptor.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||
#define COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
|
||||
class NimBLERemoteCharacteristic;
|
||||
/**
|
||||
* @brief A model of remote %BLE descriptor.
|
||||
*/
|
||||
class NimBLERemoteDescriptor {
|
||||
public:
|
||||
uint16_t getHandle();
|
||||
NimBLERemoteCharacteristic* getRemoteCharacteristic();
|
||||
NimBLEUUID getUUID();
|
||||
NimBLEAttValue readValue();
|
||||
|
||||
uint8_t readUInt8() __attribute__ ((deprecated("Use template readValue<uint8_t>()")));
|
||||
uint16_t readUInt16() __attribute__ ((deprecated("Use template readValue<uint16_t>()")));
|
||||
uint32_t readUInt32() __attribute__ ((deprecated("Use template readValue<uint32_t>()")));
|
||||
std::string toString(void);
|
||||
bool writeValue(const uint8_t* data, size_t length, bool response = false);
|
||||
bool writeValue(const std::vector<uint8_t>& v, bool response = false);
|
||||
bool writeValue(const char* s, bool response = false);
|
||||
|
||||
|
||||
/*********************** Template Functions ************************/
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote descriptor value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used for non-arrays and types without a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<!std::is_array<T>::value && !Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)&s, sizeof(T), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to set the remote descriptor value to <type\>val.
|
||||
* @param [in] s The value to write.
|
||||
* @param [in] response True == request write response.
|
||||
* @details Only used if the <type\> has a `c_str()` method.
|
||||
*/
|
||||
template<typename T>
|
||||
#ifdef _DOXYGEN_
|
||||
bool
|
||||
#else
|
||||
typename std::enable_if<Has_c_str_len<T>::value, bool>::type
|
||||
#endif
|
||||
writeValue(const T& s, bool response = false) {
|
||||
return writeValue((uint8_t*)s.c_str(), s.length(), response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Template to convert the remote descriptor data to <type\>.
|
||||
* @tparam T The type to convert the data to.
|
||||
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
|
||||
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
|
||||
* less than <tt>sizeof(<type\>)</tt>.
|
||||
* @details <b>Use:</b> <tt>readValue<type>(skipSizeCheck);</tt>
|
||||
*/
|
||||
template<typename T>
|
||||
T readValue(bool skipSizeCheck = false) {
|
||||
NimBLEAttValue value = readValue();
|
||||
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
|
||||
return *((T *)value.data());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class NimBLERemoteCharacteristic;
|
||||
|
||||
NimBLERemoteDescriptor (NimBLERemoteCharacteristic* pRemoteCharacteristic,
|
||||
const struct ble_gatt_dsc *dsc);
|
||||
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg);
|
||||
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg);
|
||||
|
||||
uint16_t m_handle;
|
||||
NimBLEUUID m_uuid;
|
||||
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTEDESCRIPTOR_H_ */
|
||||
411
lib/NimBLE-Arduino/src/NimBLERemoteService.cpp
Normal file
411
lib/NimBLE-Arduino/src/NimBLERemoteService.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* NimBLERemoteService.cpp
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteService.cpp
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLERemoteService.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLERemoteService";
|
||||
|
||||
/**
|
||||
* @brief Remote Service constructor.
|
||||
* @param [in] pClient A pointer to the client this belongs to.
|
||||
* @param [in] service A pointer to the structure with the service information.
|
||||
*/
|
||||
NimBLERemoteService::NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc* service) {
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, ">> NimBLERemoteService()");
|
||||
m_pClient = pClient;
|
||||
switch (service->uuid.u.type) {
|
||||
case BLE_UUID_TYPE_16:
|
||||
m_uuid = NimBLEUUID(service->uuid.u16.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_32:
|
||||
m_uuid = NimBLEUUID(service->uuid.u32.value);
|
||||
break;
|
||||
case BLE_UUID_TYPE_128:
|
||||
m_uuid = NimBLEUUID(const_cast<ble_uuid128_t*>(&service->uuid.u128));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_startHandle = service->start_handle;
|
||||
m_endHandle = service->end_handle;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< NimBLERemoteService(): %s", m_uuid.toString().c_str());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief When deleting the service make sure we delete all characteristics and descriptors.
|
||||
*/
|
||||
NimBLERemoteService::~NimBLERemoteService() {
|
||||
deleteCharacteristics();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the beginning of the vector of remote characteristic pointers.
|
||||
* @return An iterator to the beginning of the vector of remote characteristic pointers.
|
||||
*/
|
||||
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::begin() {
|
||||
return m_characteristicVector.begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the end of the vector of remote characteristic pointers.
|
||||
* @return An iterator to the end of the vector of remote characteristic pointers.
|
||||
*/
|
||||
std::vector<NimBLERemoteCharacteristic*>::iterator NimBLERemoteService::end() {
|
||||
return m_characteristicVector.end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote characteristic object for the characteristic UUID.
|
||||
* @param [in] uuid Remote characteristic uuid.
|
||||
* @return A pointer to the remote characteristic object.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const char* uuid) {
|
||||
return getCharacteristic(NimBLEUUID(uuid));
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic object for the UUID.
|
||||
* @param [in] uuid Characteristic uuid.
|
||||
* @return A pointer to the characteristic object, or nullptr if not found.
|
||||
*/
|
||||
NimBLERemoteCharacteristic* NimBLERemoteService::getCharacteristic(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> getCharacteristic: uuid: %s", uuid.toString().c_str());
|
||||
|
||||
for(auto &it: m_characteristicVector) {
|
||||
if(it->getUUID() == uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: found the characteristic with uuid: %s", uuid.toString().c_str());
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
size_t prev_size = m_characteristicVector.size();
|
||||
if(retrieveCharacteristics(&uuid)) {
|
||||
if(m_characteristicVector.size() > prev_size) {
|
||||
return m_characteristicVector.back();
|
||||
}
|
||||
|
||||
// If the request was successful but 16/32 bit uuid not found
|
||||
// try again with the 128 bit uuid.
|
||||
if(uuid.bitSize() == BLE_UUID_TYPE_16 ||
|
||||
uuid.bitSize() == BLE_UUID_TYPE_32)
|
||||
{
|
||||
NimBLEUUID uuid128(uuid);
|
||||
uuid128.to128();
|
||||
if (retrieveCharacteristics(&uuid128)) {
|
||||
if(m_characteristicVector.size() > prev_size) {
|
||||
return m_characteristicVector.back();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the request was successful but the 128 bit uuid not found
|
||||
// try again with the 16 bit uuid.
|
||||
NimBLEUUID uuid16(uuid);
|
||||
uuid16.to16();
|
||||
// if the uuid was 128 bit but not of the BLE base type this check will fail
|
||||
if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
|
||||
if(retrieveCharacteristics(&uuid16)) {
|
||||
if(m_characteristicVector.size() > prev_size) {
|
||||
return m_characteristicVector.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< getCharacteristic: not found");
|
||||
return nullptr;
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the vector of found characteristics.
|
||||
* @param [in] refresh If true the current characteristics vector will cleared and
|
||||
* all characteristics for this service retrieved from the peripheral.
|
||||
* If false the vector will be returned with the currently stored characteristics of this service.
|
||||
* @return A pointer to the vector of descriptors for this characteristic.
|
||||
*/
|
||||
std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics(bool refresh) {
|
||||
if(refresh) {
|
||||
deleteCharacteristics();
|
||||
|
||||
if (!retrieveCharacteristics()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get characteristics");
|
||||
}
|
||||
else{
|
||||
NIMBLE_LOGI(LOG_TAG, "Found %d characteristics", m_characteristicVector.size());
|
||||
}
|
||||
}
|
||||
return &m_characteristicVector;
|
||||
} // getCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback for Characterisic discovery.
|
||||
* @return success == 0 or error code.
|
||||
*/
|
||||
int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg)
|
||||
{
|
||||
NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
|
||||
error->status, (error->status == 0) ? chr->val_handle : -1);
|
||||
|
||||
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
|
||||
NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT;
|
||||
|
||||
// Make sure the discovery is for this device
|
||||
if(service->getClient()->getConnId() != conn_handle){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(error->status == 0) {
|
||||
// Found a service - add it to the vector
|
||||
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
|
||||
service->m_characteristicVector.push_back(pRemoteCharacteristic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(error->status == BLE_HS_EDONE) {
|
||||
pTaskData->rc = 0;
|
||||
} else {
|
||||
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
|
||||
error->status,
|
||||
NimBLEUtils::returnCodeToString(error->status));
|
||||
pTaskData->rc = error->status;
|
||||
}
|
||||
|
||||
xTaskNotifyGive(pTaskData->task);
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
|
||||
return error->status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve all the characteristics for this service.
|
||||
* This function will not return until we have all the characteristics.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
|
||||
int rc = 0;
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
|
||||
|
||||
if(uuid_filter == nullptr) {
|
||||
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
|
||||
m_startHandle,
|
||||
m_endHandle,
|
||||
NimBLERemoteService::characteristicDiscCB,
|
||||
&taskData);
|
||||
} else {
|
||||
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
|
||||
m_startHandle,
|
||||
m_endHandle,
|
||||
&uuid_filter->getNative()->u,
|
||||
NimBLERemoteService::characteristicDiscCB,
|
||||
&taskData);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
if(taskData.rc == 0){
|
||||
if (uuid_filter == nullptr) {
|
||||
if (m_characteristicVector.size() > 1) {
|
||||
for (auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it ) {
|
||||
auto nx = std::next(it, 1);
|
||||
if (nx == m_characteristicVector.end()) {
|
||||
break;
|
||||
}
|
||||
(*it)->m_endHandle = (*nx)->m_defHandle - 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_characteristicVector.back()->m_endHandle = getEndHandle();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
|
||||
return true;
|
||||
}
|
||||
|
||||
NIMBLE_LOGE(LOG_TAG, "Could not retrieve characteristics");
|
||||
return false;
|
||||
|
||||
} // retrieveCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the client associated with this service.
|
||||
* @return A reference to the client associated with this service.
|
||||
*/
|
||||
NimBLEClient* NimBLERemoteService::getClient() {
|
||||
return m_pClient;
|
||||
} // getClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service end handle.
|
||||
*/
|
||||
uint16_t NimBLERemoteService::getEndHandle() {
|
||||
return m_endHandle;
|
||||
} // getEndHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service start handle.
|
||||
*/
|
||||
uint16_t NimBLERemoteService::getStartHandle() {
|
||||
return m_startHandle;
|
||||
} // getStartHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service UUID.
|
||||
*/
|
||||
NimBLEUUID NimBLERemoteService::getUUID() {
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read the value of a characteristic associated with this service.
|
||||
* @param [in] characteristicUuid The characteristic to read.
|
||||
* @returns a string containing the value or an empty string if not found or error.
|
||||
*/
|
||||
std::string NimBLERemoteService::getValue(const NimBLEUUID &characteristicUuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
|
||||
std::string ret = "";
|
||||
NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid);
|
||||
|
||||
if(pChar != nullptr) {
|
||||
ret = pChar->readValue();
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< readValue");
|
||||
return ret;
|
||||
} // readValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a characteristic.
|
||||
* @param [in] characteristicUuid The characteristic to set.
|
||||
* @param [in] value The value to set.
|
||||
* @returns true on success, false if not found or error
|
||||
*/
|
||||
bool NimBLERemoteService::setValue(const NimBLEUUID &characteristicUuid, const std::string &value) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
|
||||
bool ret = false;
|
||||
NimBLERemoteCharacteristic* pChar = getCharacteristic(characteristicUuid);
|
||||
|
||||
if(pChar != nullptr) {
|
||||
ret = pChar->writeValue(value);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
||||
return ret;
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the characteristics in the characteristics vector.
|
||||
* @details We maintain a vector called m_characteristicsVector that contains pointers to BLERemoteCharacteristic
|
||||
* object references. Since we allocated these in this class, we are also responsible for deleting
|
||||
* them. This method does just that.
|
||||
*/
|
||||
void NimBLERemoteService::deleteCharacteristics() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristics");
|
||||
for(auto &it: m_characteristicVector) {
|
||||
delete it;
|
||||
}
|
||||
m_characteristicVector.clear();
|
||||
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics");
|
||||
} // deleteCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete characteristic by UUID
|
||||
* @param [in] uuid The UUID of the characteristic to be removed from the local database.
|
||||
* @return Number of characteristics left.
|
||||
*/
|
||||
size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic");
|
||||
|
||||
for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) {
|
||||
if((*it)->getUUID() == uuid) {
|
||||
delete *it;
|
||||
m_characteristicVector.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristic");
|
||||
|
||||
return m_characteristicVector.size();
|
||||
} // deleteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this remote service.
|
||||
* @return A string representation of this remote service.
|
||||
*/
|
||||
std::string NimBLERemoteService::toString() {
|
||||
std::string res = "Service: uuid: " + m_uuid.toString();
|
||||
char val[6];
|
||||
res += ", start_handle: ";
|
||||
snprintf(val, sizeof(val), "%d", m_startHandle);
|
||||
res += val;
|
||||
snprintf(val, sizeof(val), "%04x", m_startHandle);
|
||||
res += " 0x";
|
||||
res += val;
|
||||
res += ", end_handle: ";
|
||||
snprintf(val, sizeof(val), "%d", m_endHandle);
|
||||
res += val;
|
||||
snprintf(val, sizeof(val), "%04x", m_endHandle);
|
||||
res += " 0x";
|
||||
res += val;
|
||||
|
||||
for (auto &it: m_characteristicVector) {
|
||||
res += "\n" + it->toString();
|
||||
}
|
||||
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
85
lib/NimBLE-Arduino/src/NimBLERemoteService.h
Normal file
85
lib/NimBLE-Arduino/src/NimBLERemoteService.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* NimBLERemoteService.h
|
||||
*
|
||||
* Created: on Jan 27 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLERemoteService.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||
#define COMPONENTS_NIMBLEREMOTESERVICE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
|
||||
|
||||
#include "NimBLEClient.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLERemoteCharacteristic.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEClient;
|
||||
class NimBLERemoteCharacteristic;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a remote %BLE service.
|
||||
*/
|
||||
class NimBLERemoteService {
|
||||
public:
|
||||
virtual ~NimBLERemoteService();
|
||||
|
||||
// Public methods
|
||||
std::vector<NimBLERemoteCharacteristic*>::iterator begin();
|
||||
std::vector<NimBLERemoteCharacteristic*>::iterator end();
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const char* uuid);
|
||||
NimBLERemoteCharacteristic* getCharacteristic(const NimBLEUUID &uuid);
|
||||
void deleteCharacteristics();
|
||||
size_t deleteCharacteristic(const NimBLEUUID &uuid);
|
||||
NimBLEClient* getClient(void);
|
||||
//uint16_t getHandle();
|
||||
NimBLEUUID getUUID(void);
|
||||
std::string getValue(const NimBLEUUID &characteristicUuid);
|
||||
bool setValue(const NimBLEUUID &characteristicUuid,
|
||||
const std::string &value);
|
||||
std::string toString(void);
|
||||
std::vector<NimBLERemoteCharacteristic*>* getCharacteristics(bool refresh = false);
|
||||
|
||||
private:
|
||||
// Private constructor ... never meant to be created by a user application.
|
||||
NimBLERemoteService(NimBLEClient* pClient, const struct ble_gatt_svc *service);
|
||||
|
||||
// Friends
|
||||
friend class NimBLEClient;
|
||||
friend class NimBLERemoteCharacteristic;
|
||||
|
||||
// Private methods
|
||||
bool retrieveCharacteristics(const NimBLEUUID *uuid_filter = nullptr);
|
||||
static int characteristicDiscCB(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr,
|
||||
void *arg);
|
||||
|
||||
uint16_t getStartHandle();
|
||||
uint16_t getEndHandle();
|
||||
void releaseSemaphores();
|
||||
|
||||
// Properties
|
||||
|
||||
// We maintain a vector of characteristics owned by this service.
|
||||
std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
|
||||
|
||||
NimBLEClient* m_pClient;
|
||||
NimBLEUUID m_uuid;
|
||||
uint16_t m_startHandle;
|
||||
uint16_t m_endHandle;
|
||||
}; // NimBLERemoteService
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|
||||
#endif /* COMPONENTS_NIMBLEREMOTESERVICE_H_ */
|
||||
541
lib/NimBLE-Arduino/src/NimBLEScan.cpp
Normal file
541
lib/NimBLE-Arduino/src/NimBLEScan.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* NimBLEScan.cpp
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEScan.cpp
|
||||
*
|
||||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
#include "NimBLEScan.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <string>
|
||||
#include <climits>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEScan";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Scan constuctor.
|
||||
*/
|
||||
NimBLEScan::NimBLEScan() {
|
||||
m_scan_params.filter_policy = BLE_HCI_SCAN_FILT_NO_WL;
|
||||
m_scan_params.passive = 1; // If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).
|
||||
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
|
||||
m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)
|
||||
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
|
||||
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_ignoreResults = false;
|
||||
m_pTaskData = nullptr;
|
||||
m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset
|
||||
m_maxResults = 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Scan destructor, release any allocated resources.
|
||||
*/
|
||||
NimBLEScan::~NimBLEScan() {
|
||||
clearResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle GAP events related to scans.
|
||||
* @param [in] event The event type for this event.
|
||||
* @param [in] param Parameter data for this event.
|
||||
*/
|
||||
/*STATIC*/int NimBLEScan::handleGapEvent(ble_gap_event* event, void* arg) {
|
||||
|
||||
NimBLEScan* pScan = (NimBLEScan*)arg;
|
||||
|
||||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_DISC: {
|
||||
if(pScan->m_ignoreResults) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLEAddress advertisedAddress(event->disc.addr);
|
||||
|
||||
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
|
||||
if(NimBLEDevice::isIgnored(advertisedAddress)) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLEAdvertisedDevice* advertisedDevice = nullptr;
|
||||
|
||||
// If we've seen this device before get a pointer to it from the vector
|
||||
for(auto &it: pScan->m_scanResults.m_advertisedDevicesVector) {
|
||||
if(it->getAddress() == advertisedAddress) {
|
||||
advertisedDevice = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't seen this device before; create a new instance and insert it in the vector.
|
||||
// Otherwise just update the relevant parameters of the already known device.
|
||||
if(advertisedDevice == nullptr && event->disc.event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP){
|
||||
// Check if we have reach the scan results limit, ignore this one if so.
|
||||
// We still need to store each device when maxResults is 0 to be able to append the scan results
|
||||
if(pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
|
||||
(pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
advertisedDevice = new NimBLEAdvertisedDevice();
|
||||
advertisedDevice->setAddress(advertisedAddress);
|
||||
advertisedDevice->setAdvType(event->disc.event_type);
|
||||
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
|
||||
NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else if(advertisedDevice != nullptr) {
|
||||
NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str());
|
||||
} else {
|
||||
// Scan response from unknown device
|
||||
return 0;
|
||||
}
|
||||
|
||||
advertisedDevice->m_timestamp = time(nullptr);
|
||||
advertisedDevice->setRSSI(event->disc.rssi);
|
||||
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
|
||||
event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
|
||||
|
||||
if (pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
// If not active scanning or scan response is not available
|
||||
// report the result to the callback now.
|
||||
if(pScan->m_scan_params.passive ||
|
||||
(advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
|
||||
advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
|
||||
{
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
|
||||
// Otherwise, wait for the scan response so we can report the complete data.
|
||||
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
|
||||
advertisedDevice->m_callbackSent = true;
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
}
|
||||
// If not storing results and we have invoked the callback, delete the device.
|
||||
if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) {
|
||||
pScan->erase(advertisedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d",
|
||||
event->disc_complete.reason);
|
||||
|
||||
// If a device advertised with scan reponse available and it was not received
|
||||
// the callback would not have been invoked, so do it here.
|
||||
if(pScan->m_pAdvertisedDeviceCallbacks) {
|
||||
for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) {
|
||||
if(!it->m_callbackSent) {
|
||||
pScan->m_pAdvertisedDeviceCallbacks->onResult(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pScan->m_maxResults == 0) {
|
||||
pScan->clearResults();
|
||||
}
|
||||
|
||||
if (pScan->m_scanCompleteCB != nullptr) {
|
||||
pScan->m_scanCompleteCB(pScan->m_scanResults);
|
||||
}
|
||||
|
||||
if(pScan->m_pTaskData != nullptr) {
|
||||
pScan->m_pTaskData->rc = event->disc_complete.reason;
|
||||
xTaskNotifyGive(pScan->m_pTaskData->task);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} // gapEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Should we perform an active or passive scan?
|
||||
* The default is a passive scan. An active scan means that we will request a scan response.
|
||||
* @param [in] active If true, we perform an active scan otherwise a passive scan.
|
||||
*/
|
||||
void NimBLEScan::setActiveScan(bool active) {
|
||||
m_scan_params.passive = !active;
|
||||
} // setActiveScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set whether or not the BLE controller should only report results
|
||||
* from devices it has not already seen.
|
||||
* @param [in] enabled If true, scanned devices will only be reported once.
|
||||
* @details The controller has a limited buffer and will start reporting
|
||||
* dupicate devices once the limit is reached.
|
||||
*/
|
||||
void NimBLEScan::setDuplicateFilter(bool enabled) {
|
||||
m_scan_params.filter_duplicates = enabled;
|
||||
} // setDuplicateFilter
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set whether or not the BLE controller only report scan results
|
||||
* from devices advertising in limited discovery mode, i.e. directed advertising.
|
||||
* @param [in] enabled If true, only limited discovery devices will be in scan results.
|
||||
*/
|
||||
void NimBLEScan::setLimitedOnly(bool enabled) {
|
||||
m_scan_params.limited = enabled;
|
||||
} // setLimited
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the scan filter policy.
|
||||
* @param [in] filter Can be one of:
|
||||
* * BLE_HCI_SCAN_FILT_NO_WL (0)
|
||||
* Scanner processes all advertising packets (white list not used) except\n
|
||||
* directed, connectable advertising packets not sent to the scanner.
|
||||
* * BLE_HCI_SCAN_FILT_USE_WL (1)
|
||||
* Scanner processes advertisements from white list only. A connectable,\n
|
||||
* directed advertisment is ignored unless it contains scanners address.
|
||||
* * BLE_HCI_SCAN_FILT_NO_WL_INITA (2)
|
||||
* Scanner process all advertising packets (white list not used). A\n
|
||||
* connectable, directed advertisement shall not be ignored if the InitA
|
||||
* is a resolvable private address.
|
||||
* * BLE_HCI_SCAN_FILT_USE_WL_INITA (3)
|
||||
* Scanner process advertisements from white list only. A connectable,\n
|
||||
* directed advertisement shall not be ignored if the InitA is a
|
||||
* resolvable private address.
|
||||
*/
|
||||
void NimBLEScan::setFilterPolicy(uint8_t filter) {
|
||||
m_scan_params.filter_policy = filter;
|
||||
} // setFilterPolicy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the max number of results to store.
|
||||
* @param [in] maxResults The number of results to limit storage to\n
|
||||
* 0 == none (callbacks only) 0xFF == unlimited, any other value is the limit.
|
||||
*/
|
||||
void NimBLEScan::setMaxResults(uint8_t maxResults) {
|
||||
m_maxResults = maxResults;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the call backs to be invoked.
|
||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
||||
*/
|
||||
void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||
bool wantDuplicates) {
|
||||
setDuplicateFilter(!wantDuplicates);
|
||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||
} // setAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the interval to scan.
|
||||
* @param [in] intervalMSecs The scan interval (how often) in milliseconds.
|
||||
*/
|
||||
void NimBLEScan::setInterval(uint16_t intervalMSecs) {
|
||||
m_scan_params.itvl = intervalMSecs / 0.625;
|
||||
} // setInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the window to actively scan.
|
||||
* @param [in] windowMSecs How long to actively scan.
|
||||
*/
|
||||
void NimBLEScan::setWindow(uint16_t windowMSecs) {
|
||||
m_scan_params.window = windowMSecs / 0.625;
|
||||
} // setWindow
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the status of the scanner.
|
||||
* @return true if scanning or scan starting.
|
||||
*/
|
||||
bool NimBLEScan::isScanning() {
|
||||
return ble_gap_disc_active();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start scanning.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @param [in] scanCompleteCB A function to be called when scanning has completed.
|
||||
* @param [in] is_continue Set to true to save previous scan results, false to clear them.
|
||||
* @return True if scan started or false if there was an error.
|
||||
*/
|
||||
bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start: duration=%" PRIu32, duration);
|
||||
|
||||
// Save the callback to be invoked when the scan completes.
|
||||
m_scanCompleteCB = scanCompleteCB;
|
||||
// Save the duration in the case that the host is reset so we can reuse it.
|
||||
m_duration = duration;
|
||||
|
||||
// If 0 duration specified then we assume a continuous scan is desired.
|
||||
if(duration == 0){
|
||||
duration = BLE_HS_FOREVER;
|
||||
}
|
||||
else{
|
||||
// convert duration to milliseconds
|
||||
duration = duration * 1000;
|
||||
}
|
||||
|
||||
// Set the flag to ignore the results while we are deleting the vector
|
||||
if(!is_continue) {
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
int rc = ble_gap_disc(NimBLEDevice::m_own_addr_type, duration, &m_scan_params,
|
||||
NimBLEScan::handleGapEvent, this);
|
||||
|
||||
switch(rc) {
|
||||
case 0:
|
||||
if(!is_continue) {
|
||||
clearResults();
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EALREADY:
|
||||
// Clear the cache if already scanning in case an advertiser was missed.
|
||||
clearDuplicateCache();
|
||||
break;
|
||||
|
||||
case BLE_HS_EBUSY:
|
||||
NIMBLE_LOGE(LOG_TAG, "Unable to scan - connection in progress.");
|
||||
break;
|
||||
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Unable to scan - Host Reset");
|
||||
break;
|
||||
|
||||
default:
|
||||
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
|
||||
rc, NimBLEUtils::returnCodeToString(rc));
|
||||
break;
|
||||
}
|
||||
|
||||
m_ignoreResults = false;
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
|
||||
if(rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start scanning and block until scanning has been completed.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @param [in] is_continue Set to true to save previous scan results, false to clear them.
|
||||
* @return The NimBLEScanResults.
|
||||
*/
|
||||
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
|
||||
if(duration == 0) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
|
||||
}
|
||||
|
||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||
ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
|
||||
m_pTaskData = &taskData;
|
||||
|
||||
if(start(duration, nullptr, is_continue)) {
|
||||
#ifdef ulTaskNotifyValueClear
|
||||
// Clear the task notification value to ensure we block
|
||||
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
||||
#endif
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
}
|
||||
|
||||
m_pTaskData = nullptr;
|
||||
return m_scanResults;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop an in progress scan.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool NimBLEScan::stop() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> stop()");
|
||||
|
||||
int rc = ble_gap_disc_cancel();
|
||||
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_maxResults == 0) {
|
||||
clearResults();
|
||||
}
|
||||
|
||||
if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) {
|
||||
m_scanCompleteCB(m_scanResults);
|
||||
}
|
||||
|
||||
if(m_pTaskData != nullptr) {
|
||||
xTaskNotifyGive(m_pTaskData->task);
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< stop()");
|
||||
return true;
|
||||
} // stop
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clears the duplicate scan filter cache.
|
||||
*/
|
||||
void NimBLEScan::clearDuplicateCache() {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32 // Not available for ESP32C3
|
||||
esp_ble_scan_dupilcate_list_flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete peer device from the scan results vector.
|
||||
* @param [in] address The address of the device to delete from the results.
|
||||
* @details After disconnecting, it may be required in the case we were connected to a device without a public address.
|
||||
*/
|
||||
void NimBLEScan::erase(const NimBLEAddress &address) {
|
||||
NIMBLE_LOGD(LOG_TAG, "erase device: %s", address.toString().c_str());
|
||||
|
||||
for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) {
|
||||
if((*it)->getAddress() == address) {
|
||||
delete *it;
|
||||
m_scanResults.m_advertisedDevicesVector.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called when host reset, we set a flag to stop scanning until synced.
|
||||
*/
|
||||
void NimBLEScan::onHostReset() {
|
||||
m_ignoreResults = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief If the host reset and re-synced this is called.
|
||||
* If the application was scanning indefinitely with a callback, restart it.
|
||||
*/
|
||||
void NimBLEScan::onHostSync() {
|
||||
m_ignoreResults = false;
|
||||
|
||||
if(m_duration == 0 && m_pAdvertisedDeviceCallbacks != nullptr) {
|
||||
start(m_duration, m_scanCompleteCB);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the results of the scan.
|
||||
* @return NimBLEScanResults object.
|
||||
*/
|
||||
NimBLEScanResults NimBLEScan::getResults() {
|
||||
return m_scanResults;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clear the results of the scan.
|
||||
*/
|
||||
void NimBLEScan::clearResults() {
|
||||
for(auto &it: m_scanResults.m_advertisedDevicesVector) {
|
||||
delete it;
|
||||
}
|
||||
m_scanResults.m_advertisedDevicesVector.clear();
|
||||
clearDuplicateCache();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dump the scan results to the log.
|
||||
*/
|
||||
void NimBLEScanResults::dump() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> Dump scan results:");
|
||||
for (int i=0; i<getCount(); i++) {
|
||||
NIMBLE_LOGI(LOG_TAG, "- %s", getDevice(i).toString().c_str());
|
||||
}
|
||||
} // dump
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the count of devices found in the last scan.
|
||||
* @return The number of devices found in the last scan.
|
||||
*/
|
||||
int NimBLEScanResults::getCount() {
|
||||
return m_advertisedDevicesVector.size();
|
||||
} // getCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the specified device at the given index.
|
||||
* The index should be between 0 and getCount()-1.
|
||||
* @param [in] i The index of the device.
|
||||
* @return The device at the specified index.
|
||||
*/
|
||||
NimBLEAdvertisedDevice NimBLEScanResults::getDevice(uint32_t i) {
|
||||
return *m_advertisedDevicesVector[i];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the beginning of the vector of advertised device pointers.
|
||||
* @return An iterator to the beginning of the vector of advertised device pointers.
|
||||
*/
|
||||
std::vector<NimBLEAdvertisedDevice*>::iterator NimBLEScanResults::begin() {
|
||||
return m_advertisedDevicesVector.begin();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get iterator to the end of the vector of advertised device pointers.
|
||||
* @return An iterator to the end of the vector of advertised device pointers.
|
||||
*/
|
||||
std::vector<NimBLEAdvertisedDevice*>::iterator NimBLEScanResults::end() {
|
||||
return m_advertisedDevicesVector.end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the specified device at the given address.
|
||||
* If the address is not found a nullptr is returned.
|
||||
* @param [in] address The address of the device.
|
||||
* @return A pointer to the device at the specified address.
|
||||
*/
|
||||
NimBLEAdvertisedDevice *NimBLEScanResults::getDevice(const NimBLEAddress &address) {
|
||||
for(size_t index = 0; index < m_advertisedDevicesVector.size(); index++) {
|
||||
if(m_advertisedDevicesVector[index]->getAddress() == address) {
|
||||
return m_advertisedDevicesVector[index];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
103
lib/NimBLE-Arduino/src/NimBLEScan.h
Normal file
103
lib/NimBLE-Arduino/src/NimBLEScan.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* NimBLEScan.h
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEScan.h
|
||||
*
|
||||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#ifndef COMPONENTS_NIMBLE_SCAN_H_
|
||||
#define COMPONENTS_NIMBLE_SCAN_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
|
||||
|
||||
#include "NimBLEAdvertisedDevice.h"
|
||||
#include "NimBLEUtils.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
class NimBLEDevice;
|
||||
class NimBLEScan;
|
||||
class NimBLEAdvertisedDevice;
|
||||
class NimBLEAdvertisedDeviceCallbacks;
|
||||
class NimBLEAddress;
|
||||
|
||||
/**
|
||||
* @brief A class that contains and operates on the results of a BLE scan.
|
||||
* @details When a scan completes, we have a set of found devices. Each device is described
|
||||
* by a NimBLEAdvertisedDevice object. The number of items in the set is given by
|
||||
* getCount(). We can retrieve a device by calling getDevice() passing in the
|
||||
* index (starting at 0) of the desired device.
|
||||
*/
|
||||
class NimBLEScanResults {
|
||||
public:
|
||||
void dump();
|
||||
int getCount();
|
||||
NimBLEAdvertisedDevice getDevice(uint32_t i);
|
||||
std::vector<NimBLEAdvertisedDevice*>::iterator begin();
|
||||
std::vector<NimBLEAdvertisedDevice*>::iterator end();
|
||||
NimBLEAdvertisedDevice *getDevice(const NimBLEAddress &address);
|
||||
|
||||
private:
|
||||
friend NimBLEScan;
|
||||
std::vector<NimBLEAdvertisedDevice*> m_advertisedDevicesVector;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE scans.
|
||||
*
|
||||
* Scanning is associated with a %BLE client that is attempting to locate BLE servers.
|
||||
*/
|
||||
class NimBLEScan {
|
||||
public:
|
||||
bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false);
|
||||
NimBLEScanResults start(uint32_t duration, bool is_continue = false);
|
||||
bool isScanning();
|
||||
void setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates = false);
|
||||
void setActiveScan(bool active);
|
||||
void setInterval(uint16_t intervalMSecs);
|
||||
void setWindow(uint16_t windowMSecs);
|
||||
void setDuplicateFilter(bool enabled);
|
||||
void setLimitedOnly(bool enabled);
|
||||
void setFilterPolicy(uint8_t filter);
|
||||
void clearDuplicateCache();
|
||||
bool stop();
|
||||
void clearResults();
|
||||
NimBLEScanResults getResults();
|
||||
void setMaxResults(uint8_t maxResults);
|
||||
void erase(const NimBLEAddress &address);
|
||||
|
||||
|
||||
private:
|
||||
friend class NimBLEDevice;
|
||||
|
||||
NimBLEScan();
|
||||
~NimBLEScan();
|
||||
static int handleGapEvent(ble_gap_event* event, void* arg);
|
||||
void onHostReset();
|
||||
void onHostSync();
|
||||
|
||||
NimBLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
void (*m_scanCompleteCB)(NimBLEScanResults scanResults);
|
||||
ble_gap_disc_params m_scan_params;
|
||||
bool m_ignoreResults;
|
||||
NimBLEScanResults m_scanResults;
|
||||
uint32_t m_duration;
|
||||
ble_task_data_t *m_pTaskData;
|
||||
uint8_t m_maxResults;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED CONFIG_BT_NIMBLE_ROLE_OBSERVER */
|
||||
#endif /* COMPONENTS_NIMBLE_SCAN_H_ */
|
||||
158
lib/NimBLE-Arduino/src/NimBLESecurity.cpp
Normal file
158
lib/NimBLE-Arduino/src/NimBLESecurity.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* NimBLESecurity.cpp
|
||||
*
|
||||
* Created: on Feb 22 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLESecurity.cpp
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
NimBLESecurity::NimBLESecurity() {
|
||||
}
|
||||
|
||||
NimBLESecurity::~NimBLESecurity() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set requested authentication mode
|
||||
* @param [in] auth_req A bitmask containing one or more of:
|
||||
* * ESP_LE_AUTH_NO_BOND 0x00
|
||||
* * ESP_LE_AUTH_BOND 0x01
|
||||
* * ESP_LE_AUTH_REQ_MITM (1 << 2)
|
||||
* * ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)
|
||||
* * ESP_LE_AUTH_REQ_SC_ONLY (1 << 3)
|
||||
* * ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY)
|
||||
* * ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY)
|
||||
* * ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND)
|
||||
*/
|
||||
void NimBLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) {
|
||||
NimBLEDevice::setSecurityAuth((auth_req & BLE_SM_PAIR_AUTHREQ_BOND)>0,
|
||||
(auth_req & BLE_SM_PAIR_AUTHREQ_MITM)>0,
|
||||
(auth_req & BLE_SM_PAIR_AUTHREQ_SC)>0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set our device IO capability to let end user perform authorization
|
||||
* either by displaying or entering generated 6-digit pin code or use \"just works\".
|
||||
* @param [in] iocap The IO capabilites our device has.\n
|
||||
* Can be set to one of:
|
||||
* * ESP_IO_CAP_OUT 0
|
||||
* * ESP_IO_CAP_IO 1
|
||||
* * ESP_IO_CAP_IN 2
|
||||
* * ESP_IO_CAP_NONE 3
|
||||
* * ESP_IO_CAP_KBDISP 4
|
||||
*/
|
||||
void NimBLESecurity::setCapability(esp_ble_io_cap_t iocap) {
|
||||
NimBLEDevice::setSecurityIOCap(iocap);
|
||||
} // setCapability
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the keys we will distibute during encryption.
|
||||
* @param [in] init_key A bitmask of the keys we will distibute.\n
|
||||
* Can be one or more of:
|
||||
* * ESP_BLE_ENC_KEY_MASK (1 << 0)
|
||||
* * ESP_BLE_ID_KEY_MASK (1 << 1)
|
||||
* * ESP_BLE_CSR_KEY_MASK (1 << 2)
|
||||
* * ESP_BLE_LINK_KEY_MASK (1 << 3)
|
||||
*/
|
||||
void NimBLESecurity::setInitEncryptionKey(uint8_t init_key) {
|
||||
NimBLEDevice::setSecurityInitKey(init_key);
|
||||
} // setInitEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the keys we will accept during encryption.
|
||||
* @param [in] resp_key A bitmask of the keys we will accept.\n
|
||||
* Can be one or more of:
|
||||
* * ESP_BLE_ENC_KEY_MASK (1 << 0)
|
||||
* * ESP_BLE_ID_KEY_MASK (1 << 1)
|
||||
* * ESP_BLE_CSR_KEY_MASK (1 << 2)
|
||||
* * ESP_BLE_LINK_KEY_MASK (1 << 3)
|
||||
*/
|
||||
void NimBLESecurity::setRespEncryptionKey(uint8_t resp_key) {
|
||||
NimBLEDevice::setSecurityRespKey(resp_key);
|
||||
} // setRespEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
*@todo Requires implementation
|
||||
*/
|
||||
void NimBLESecurity::setKeySize(uint8_t key_size) {
|
||||
|
||||
//m_keySize = key_size;
|
||||
//esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t));
|
||||
} //setKeySize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets a static PIN used to authenticate/encrypt the connection.
|
||||
* @param [in] pin The 6 digit pin code to accept.
|
||||
*/
|
||||
void NimBLESecurity::setStaticPIN(uint32_t pin){
|
||||
//uint32_t passkey = pin;
|
||||
//esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
|
||||
NimBLEDevice::setSecurityPasskey(pin);
|
||||
setCapability(ESP_IO_CAP_OUT);
|
||||
setKeySize();
|
||||
setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY);
|
||||
setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Debug function to display what keys are exchanged by peers
|
||||
*/
|
||||
/*
|
||||
char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) {
|
||||
char* key_str = nullptr;
|
||||
switch (key_type) {
|
||||
case ESP_LE_KEY_NONE:
|
||||
key_str = (char*) "ESP_LE_KEY_NONE";
|
||||
break;
|
||||
case ESP_LE_KEY_PENC:
|
||||
key_str = (char*) "ESP_LE_KEY_PENC";
|
||||
break;
|
||||
case ESP_LE_KEY_PID:
|
||||
key_str = (char*) "ESP_LE_KEY_PID";
|
||||
break;
|
||||
case ESP_LE_KEY_PCSRK:
|
||||
key_str = (char*) "ESP_LE_KEY_PCSRK";
|
||||
break;
|
||||
case ESP_LE_KEY_PLK:
|
||||
key_str = (char*) "ESP_LE_KEY_PLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LLK:
|
||||
key_str = (char*) "ESP_LE_KEY_LLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LENC:
|
||||
key_str = (char*) "ESP_LE_KEY_LENC";
|
||||
break;
|
||||
case ESP_LE_KEY_LID:
|
||||
key_str = (char*) "ESP_LE_KEY_LID";
|
||||
break;
|
||||
case ESP_LE_KEY_LCSRK:
|
||||
key_str = (char*) "ESP_LE_KEY_LCSRK";
|
||||
break;
|
||||
default:
|
||||
key_str = (char*) "INVALID BLE KEY TYPE";
|
||||
break;
|
||||
}
|
||||
return key_str;
|
||||
|
||||
} // esp_key_type_to_str
|
||||
*/
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
131
lib/NimBLE-Arduino/src/NimBLESecurity.h
Normal file
131
lib/NimBLE-Arduino/src/NimBLESecurity.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* NimBLESecurity.h
|
||||
*
|
||||
* Created: on Feb 22 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLESecurity.h
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLESECURITY_H_
|
||||
#define COMPONENTS_NIMBLESECURITY_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/
|
||||
#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) /*!< 1101 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM_BOND in stack/btm_api.h */
|
||||
|
||||
#define ESP_IO_CAP_OUT 0 /*!< DisplayOnly */ /* relate to BTM_IO_CAP_OUT in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_IO 1 /*!< DisplayYesNo */ /* relate to BTM_IO_CAP_IO in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_IN 2 /*!< KeyboardOnly */ /* relate to BTM_IO_CAP_IN in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_NONE 3 /*!< NoInputNoOutput */ /* relate to BTM_IO_CAP_NONE in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_KBDISP 4 /*!< Keyboard display */ /* relate to BTM_IO_CAP_KBDISP in stack/btm_api.h */
|
||||
|
||||
/// Used to exchange the encryption key in the initialize key & response key
|
||||
#define ESP_BLE_ENC_KEY_MASK (1 << 0) /* relate to BTM_BLE_ENC_KEY_MASK in stack/btm_api.h */
|
||||
/// Used to exchange the IRK key in the initialize key & response key
|
||||
#define ESP_BLE_ID_KEY_MASK (1 << 1) /* relate to BTM_BLE_ID_KEY_MASK in stack/btm_api.h */
|
||||
/// Used to exchange the CSRK key in the initialize key & response key
|
||||
#define ESP_BLE_CSR_KEY_MASK (1 << 2) /* relate to BTM_BLE_CSR_KEY_MASK in stack/btm_api.h */
|
||||
/// Used to exchange the link key(this key just used in the BLE & BR/EDR coexist mode) in the initialize key & response key
|
||||
#define ESP_BLE_LINK_KEY_MASK (1 << 3) /* relate to BTM_BLE_LINK_KEY_MASK in stack/btm_api.h */
|
||||
|
||||
typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit pattern */
|
||||
typedef uint8_t esp_ble_io_cap_t; /*!< combination of the io capability */
|
||||
|
||||
|
||||
/**
|
||||
* @brief A class to handle BLE security operations.
|
||||
* <b>Deprecated - provided for backward compatibility only.</b>
|
||||
* @deprecated Use the security methods provided in NimBLEDevice instead.
|
||||
*/
|
||||
class NimBLESecurity {
|
||||
public:
|
||||
NimBLESecurity();
|
||||
virtual ~NimBLESecurity();
|
||||
void setAuthenticationMode(esp_ble_auth_req_t auth_req);
|
||||
void setCapability(esp_ble_io_cap_t iocap);
|
||||
void setInitEncryptionKey(uint8_t init_key);
|
||||
void setRespEncryptionKey(uint8_t resp_key);
|
||||
void setKeySize(uint8_t key_size = 16);
|
||||
void setStaticPIN(uint32_t pin);
|
||||
//static char* esp_key_type_to_str(esp_ble_key_type_t key_type);
|
||||
/*
|
||||
private:
|
||||
esp_ble_auth_req_t m_authReq;
|
||||
esp_ble_io_cap_t m_iocap;
|
||||
uint8_t m_initKey;
|
||||
uint8_t m_respKey;
|
||||
uint8_t m_keySize;
|
||||
*/
|
||||
}; // BLESecurity
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks to handle GAP events related to authorization.
|
||||
* <b>Deprecated - provided for backward compatibility only.</b>
|
||||
* @deprecated Use the callbacks provided in NimBLEClientCallbacks and NimBLEServerCallbacks instead.
|
||||
*/
|
||||
class NimBLESecurityCallbacks {
|
||||
public:
|
||||
virtual ~NimBLESecurityCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Its request from peer device to input authentication pin code displayed on peer device.
|
||||
* It requires that our device is capable to input 6-digits code by end user
|
||||
* @return Return 6-digits integer value from input device
|
||||
*/
|
||||
virtual uint32_t onPassKeyRequest() = 0;
|
||||
|
||||
/**
|
||||
* @brief Provide us 6-digits code to perform authentication.
|
||||
* It requires that our device is capable to display this code to end user
|
||||
* @param [in] pass_key The PIN provided by the peer.
|
||||
*/
|
||||
virtual void onPassKeyNotify(uint32_t pass_key) = 0;
|
||||
|
||||
/**
|
||||
* @brief Here we can make decision if we want to let negotiate authorization with peer device or not
|
||||
* @return Return true if we accept this peer device request
|
||||
*/
|
||||
virtual bool onSecurityRequest() = 0 ;
|
||||
/**
|
||||
* @brief Provides us information when authentication process is completed
|
||||
*/
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc*) = 0;
|
||||
|
||||
/**
|
||||
* @brief Called when using numeric comparison for authentication.
|
||||
* @param [in] pin The PIN to compare.
|
||||
* @return True to accept and pair.
|
||||
*/
|
||||
virtual bool onConfirmPIN(uint32_t pin) = 0;
|
||||
}; // BLESecurityCallbacks
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // COMPONENTS_NIMBLESECURITY_H_
|
||||
867
lib/NimBLE-Arduino/src/NimBLEServer.cpp
Normal file
867
lib/NimBLE-Arduino/src/NimBLEServer.cpp
Normal file
@@ -0,0 +1,867 @@
|
||||
/*
|
||||
* NimBLEServer.cpp
|
||||
*
|
||||
* Created: on March 2, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEServer.cpp
|
||||
*
|
||||
* Created on: Apr 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEServer.h"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
|
||||
#include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
|
||||
#endif
|
||||
|
||||
static const char* LOG_TAG = "NimBLEServer";
|
||||
static NimBLEServerCallbacks defaultCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a %BLE Server
|
||||
*
|
||||
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
||||
* the NimBLEDevice class.
|
||||
*/
|
||||
NimBLEServer::NimBLEServer() {
|
||||
memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
|
||||
// m_svcChgChrHdl = 0xffff; // Future Use
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
m_gattsStarted = false;
|
||||
m_advertiseOnDisconnect = true;
|
||||
m_svcChanged = false;
|
||||
m_deleteCallbacks = true;
|
||||
} // NimBLEServer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor: frees all resources / attributes created.
|
||||
*/
|
||||
NimBLEServer::~NimBLEServer() {
|
||||
for(auto &it : m_svcVec) {
|
||||
delete it;
|
||||
}
|
||||
|
||||
if(m_deleteCallbacks && m_pServerCallbacks != &defaultCallbacks) {
|
||||
delete m_pServerCallbacks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a %BLE Service.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::createService(const char* uuid) {
|
||||
return createService(NimBLEUUID(uuid));
|
||||
} // createService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a %BLE Service.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||
|
||||
// Check that a service with the supplied UUID does not already exist.
|
||||
if(getServiceByUUID(uuid) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||
std::string(uuid).c_str());
|
||||
}
|
||||
|
||||
NimBLEService* pService = new NimBLEService(uuid);
|
||||
m_svcVec.push_back(pService);
|
||||
serviceChanged();
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< createService");
|
||||
return pService;
|
||||
} // createService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) {
|
||||
return getServiceByUUID(NimBLEUUID(uuid), instanceId);
|
||||
} // getServiceByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param instanceId The index of the service to return (used when multiple services have the same UUID).
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) {
|
||||
uint16_t position = 0;
|
||||
for (auto &it : m_svcVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
if (position == instanceId){
|
||||
return it;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} // getServiceByUUID
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its handle
|
||||
* @param handle The handle of the service.
|
||||
* @return A pointer to the service object or nullptr if not found.
|
||||
*/
|
||||
NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
|
||||
for (auto &it : m_svcVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
*
|
||||
* @return An advertising object.
|
||||
*/
|
||||
NimBLEAdvertising* NimBLEServer::getAdvertising() {
|
||||
return NimBLEDevice::getAdvertising();
|
||||
} // getAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends a service changed notification and resets the GATT server.
|
||||
*/
|
||||
void NimBLEServer::serviceChanged() {
|
||||
if(m_gattsStarted) {
|
||||
m_svcChanged = true;
|
||||
ble_svc_gatt_changed(0x0001, 0xffff);
|
||||
resetGATT();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the GATT server. Required to be called after setup of all
|
||||
* services and characteristics / descriptors for the NimBLE host to register them.
|
||||
*/
|
||||
void NimBLEServer::start() {
|
||||
if(m_gattsStarted) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Gatt server already started");
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = ble_gatts_start();
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_start; rc=%d, %s", rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
abort();
|
||||
}
|
||||
|
||||
#if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
|
||||
ble_gatts_show_local();
|
||||
#endif
|
||||
/*** Future use ***
|
||||
* TODO: implement service changed handling
|
||||
|
||||
ble_uuid16_t svc = {BLE_UUID_TYPE_16, 0x1801};
|
||||
ble_uuid16_t chr = {BLE_UUID_TYPE_16, 0x2a05};
|
||||
|
||||
rc = ble_gatts_find_chr(&svc.u, &chr.u, NULL, &m_svcChgChrHdl);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_find_chr: rc=%d, %s", rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
abort();
|
||||
}
|
||||
|
||||
NIMBLE_LOGI(LOG_TAG, "Service changed characterisic handle: %d", m_svcChgChrHdl);
|
||||
*/
|
||||
// Get the assigned service handles and build a vector of characteristics
|
||||
// with Notify / Indicate capabilities for event handling
|
||||
for(auto &svc : m_svcVec) {
|
||||
if(svc->m_removed == 0) {
|
||||
rc = ble_gatts_find_svc(&svc->getUUID().getNative()->u, &svc->m_handle);
|
||||
if(rc != 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &chr : svc->m_chrVec) {
|
||||
// if Notify / Indicate is enabled but we didn't create the descriptor
|
||||
// we do it now.
|
||||
if((chr->m_properties & BLE_GATT_CHR_F_INDICATE) ||
|
||||
(chr->m_properties & BLE_GATT_CHR_F_NOTIFY)) {
|
||||
m_notifyChrVec.push_back(chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_gattsStarted = true;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Disconnect the specified client with optional reason.
|
||||
* @param [in] connId Connection Id of the client to disconnect.
|
||||
* @param [in] reason code for disconnecting.
|
||||
* @return NimBLE host return code.
|
||||
*/
|
||||
int NimBLEServer::disconnect(uint16_t connId, uint8_t reason) {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> disconnect()");
|
||||
|
||||
int rc = ble_gap_terminate(connId, reason);
|
||||
if(rc != 0){
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gap_terminate failed: rc=%d %s", rc,
|
||||
NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< disconnect()");
|
||||
return rc;
|
||||
} // disconnect
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the server to automatically start advertising when a client disconnects.
|
||||
* @param [in] aod true == advertise, false == don't advertise.
|
||||
*/
|
||||
void NimBLEServer::advertiseOnDisconnect(bool aod) {
|
||||
m_advertiseOnDisconnect = aod;
|
||||
} // advertiseOnDisconnect
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the number of connected clients.
|
||||
* @return The number of connected clients.
|
||||
*/
|
||||
size_t NimBLEServer::getConnectedCount() {
|
||||
return m_connectedPeersVec.size();
|
||||
} // getConnectedCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the vector of the connected client ID's.
|
||||
*/
|
||||
std::vector<uint16_t> NimBLEServer::getPeerDevices() {
|
||||
return m_connectedPeersVec;
|
||||
} // getPeerDevices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by vector index.
|
||||
* @param [in] index The vector index of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) {
|
||||
if (index >= m_connectedPeersVec.size()) {
|
||||
NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index);
|
||||
return NimBLEConnInfo();
|
||||
}
|
||||
|
||||
return getPeerIDInfo(m_connectedPeersVec[index]);
|
||||
} // getPeerInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by address.
|
||||
* @param [in] address The address of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) {
|
||||
ble_addr_t peerAddr;
|
||||
memcpy(&peerAddr.val, address.getNative(),6);
|
||||
peerAddr.type = address.getType();
|
||||
|
||||
NimBLEConnInfo peerInfo;
|
||||
int rc = ble_gap_conn_find_by_addr(&peerAddr, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
||||
}
|
||||
|
||||
return peerInfo;
|
||||
} // getPeerInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the connection information of a connected peer by connection ID.
|
||||
* @param [in] id The connection id of the peer.
|
||||
*/
|
||||
NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
|
||||
NimBLEConnInfo peerInfo;
|
||||
|
||||
int rc = ble_gap_conn_find(id, &peerInfo.m_desc);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
|
||||
}
|
||||
|
||||
return peerInfo;
|
||||
} // getPeerIDInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a GATT Server Event.
|
||||
*
|
||||
* @param [in] event
|
||||
* @param [in] gatts_if
|
||||
* @param [in] param
|
||||
*
|
||||
*/
|
||||
/*STATIC*/
|
||||
int NimBLEServer::handleGapEvent(struct ble_gap_event *event, void *arg) {
|
||||
NimBLEServer* server = (NimBLEServer*)arg;
|
||||
NIMBLE_LOGD(LOG_TAG, ">> handleGapEvent: %s",
|
||||
NimBLEUtils::gapEventToString(event->type));
|
||||
int rc = 0;
|
||||
struct ble_gap_conn_desc desc;
|
||||
|
||||
switch(event->type) {
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
NIMBLE_LOGE(LOG_TAG, "Connection failed");
|
||||
NimBLEDevice::startAdvertising();
|
||||
}
|
||||
else {
|
||||
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onConnect(server);
|
||||
server->m_pServerCallbacks->onConnect(server, &desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_CONNECT
|
||||
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
// If Host reset tell the device now before returning to prevent
|
||||
// any errors caused by calling host functions before resyncing.
|
||||
switch(event->disconnect.reason) {
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
case BLE_HS_EOS:
|
||||
case BLE_HS_ECONTROLLER:
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
NIMBLE_LOGC(LOG_TAG, "Disconnect - host reset, rc=%d", event->disconnect.reason);
|
||||
NimBLEDevice::onReset(event->disconnect.reason);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
server->m_connectedPeersVec.erase(std::remove(server->m_connectedPeersVec.begin(),
|
||||
server->m_connectedPeersVec.end(),
|
||||
event->disconnect.conn.conn_handle),
|
||||
server->m_connectedPeersVec.end());
|
||||
|
||||
if(server->m_svcChanged) {
|
||||
server->resetGATT();
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onDisconnect(server);
|
||||
server->m_pServerCallbacks->onDisconnect(server, &event->disconnect.conn);
|
||||
|
||||
if(server->m_advertiseOnDisconnect) {
|
||||
server->startAdvertising();
|
||||
}
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_DISCONNECT
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE: {
|
||||
NIMBLE_LOGI(LOG_TAG, "subscribe event; attr_handle=%d, subscribed: %s",
|
||||
event->subscribe.attr_handle,
|
||||
(event->subscribe.cur_notify ? "true":"false"));
|
||||
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->subscribe.attr_handle) {
|
||||
if((it->getProperties() & BLE_GATT_CHR_F_READ_AUTHEN) ||
|
||||
(it->getProperties() & BLE_GATT_CHR_F_READ_AUTHOR) ||
|
||||
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
|
||||
{
|
||||
rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
|
||||
if (rc != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!desc.sec_state.encrypted) {
|
||||
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
|
||||
}
|
||||
}
|
||||
|
||||
it->setSubscribe(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_SUBSCRIBE
|
||||
|
||||
case BLE_GAP_EVENT_MTU: {
|
||||
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
rc = ble_gap_conn_find(event->mtu.conn_handle, &desc);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->m_pServerCallbacks->onMTUChange(event->mtu.value, &desc);
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_MTU
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX: {
|
||||
NimBLECharacteristic *pChar = nullptr;
|
||||
|
||||
for(auto &it : server->m_notifyChrVec) {
|
||||
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||
pChar = it;
|
||||
}
|
||||
}
|
||||
|
||||
if(pChar == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NimBLECharacteristicCallbacks::Status statusRC;
|
||||
|
||||
if(event->notify_tx.indication) {
|
||||
if(event->notify_tx.status != 0) {
|
||||
if(event->notify_tx.status == BLE_HS_EDONE) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
|
||||
} else if(rc == BLE_HS_ETIMEOUT) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->clearIndicateWait(event->notify_tx.conn_handle);
|
||||
} else {
|
||||
if(event->notify_tx.status == 0) {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
|
||||
} else {
|
||||
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
|
||||
}
|
||||
}
|
||||
|
||||
pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status);
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_NOTIFY_TX
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Advertising Complete");
|
||||
NimBLEDevice::getAdvertising()->advCompleteCB();
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE: {
|
||||
NIMBLE_LOGD(LOG_TAG, "Connection parameters updated.");
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_CONN_UPDATE
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
/* We already have a bond with the peer, but it is attempting to
|
||||
* establish a new secure link. This app sacrifices security for
|
||||
* convenience: just throw away the old bond and accept the new link.
|
||||
*/
|
||||
|
||||
/* Delete the old bond. */
|
||||
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
||||
if (rc != 0){
|
||||
return BLE_GAP_REPEAT_PAIRING_IGNORE;
|
||||
}
|
||||
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
|
||||
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
|
||||
* continue with the pairing operation.
|
||||
*/
|
||||
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
||||
} // BLE_GAP_EVENT_REPEAT_PAIRING
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE: {
|
||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||
if(rc != 0) {
|
||||
return BLE_ATT_ERR_INVALID_HANDLE;
|
||||
}
|
||||
// Compatibility only - Do not use, should be removed the in future
|
||||
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
||||
NimBLEDevice::m_securityCallbacks->onAuthenticationComplete(&desc);
|
||||
/////////////////////////////////////////////
|
||||
} else {
|
||||
server->m_pServerCallbacks->onAuthenticationComplete(&desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_ENC_CHANGE
|
||||
|
||||
case BLE_GAP_EVENT_PASSKEY_ACTION: {
|
||||
struct ble_sm_io pkey = {0,0};
|
||||
|
||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||
pkey.action = event->passkey.params.action;
|
||||
// backward compatibility
|
||||
pkey.passkey = NimBLEDevice::getSecurityPasskey(); // This is the passkey to be entered on peer
|
||||
// if the (static)passkey is the default, check the callback for custom value
|
||||
// both values default to the same.
|
||||
if(pkey.passkey == 123456) {
|
||||
pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest();
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_DISP; ble_sm_inject_io result: %d", rc);
|
||||
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Passkey on device's display: %" PRIu32, event->passkey.params.numcmp);
|
||||
pkey.action = event->passkey.params.action;
|
||||
// Compatibility only - Do not use, should be removed the in future
|
||||
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
||||
pkey.numcmp_accept = NimBLEDevice::m_securityCallbacks->onConfirmPIN(event->passkey.params.numcmp);
|
||||
/////////////////////////////////////////////
|
||||
} else {
|
||||
pkey.numcmp_accept = server->m_pServerCallbacks->onConfirmPIN(event->passkey.params.numcmp);
|
||||
}
|
||||
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_NUMCMP; ble_sm_inject_io result: %d", rc);
|
||||
|
||||
//TODO: Handle out of band pairing
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
||||
static uint8_t tem_oob[16] = {0};
|
||||
pkey.action = event->passkey.params.action;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
pkey.oob[i] = tem_oob[i];
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_OOB; ble_sm_inject_io result: %d", rc);
|
||||
//////////////////////////////////
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
||||
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
||||
pkey.action = event->passkey.params.action;
|
||||
|
||||
// Compatibility only - Do not use, should be removed the in future
|
||||
if(NimBLEDevice::m_securityCallbacks != nullptr) {
|
||||
pkey.passkey = NimBLEDevice::m_securityCallbacks->onPassKeyRequest();
|
||||
/////////////////////////////////////////////
|
||||
} else {
|
||||
pkey.passkey = server->m_pServerCallbacks->onPassKeyRequest();
|
||||
}
|
||||
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
NIMBLE_LOGD(LOG_TAG, "BLE_SM_IOACT_INPUT; ble_sm_inject_io result: %d", rc);
|
||||
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NONE) {
|
||||
NIMBLE_LOGD(LOG_TAG, "No passkey action required");
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
return 0;
|
||||
} // BLE_GAP_EVENT_PASSKEY_ACTION
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
return 0;
|
||||
} // handleGapEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the server callbacks.
|
||||
*
|
||||
* As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client
|
||||
* disconnecting. This function can be called to register a callback handler that will be invoked when these
|
||||
* events are detected.
|
||||
*
|
||||
* @param [in] pCallbacks The callbacks to be invoked.
|
||||
* @param [in] deleteCallbacks if true callback class will be deleted when server is destructed.
|
||||
*/
|
||||
void NimBLEServer::setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks) {
|
||||
if (pCallbacks != nullptr){
|
||||
m_pServerCallbacks = pCallbacks;
|
||||
m_deleteCallbacks = deleteCallbacks;
|
||||
} else {
|
||||
m_pServerCallbacks = &defaultCallbacks;
|
||||
}
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a service from the server.
|
||||
*
|
||||
* @details Immediately removes access to the service by clients, sends a service changed indication,
|
||||
* and removes the service (if applicable) from the advertisments.
|
||||
* The service is not deleted unless the deleteSvc parameter is true, otherwise the service remains
|
||||
* available and can be re-added in the future. If desired a removed but not deleted service can
|
||||
* be deleted later by calling this method with deleteSvc set to true.
|
||||
*
|
||||
* @note The service will not be removed from the database until all open connections are closed
|
||||
* as it requires resetting the GATT server. In the interim the service will have it's visibility disabled.
|
||||
*
|
||||
* @note Advertising will need to be restarted by the user after calling this as we must stop
|
||||
* advertising in order to remove the service.
|
||||
*
|
||||
* @param [in] service The service object to remove.
|
||||
* @param [in] deleteSvc true if the service should be deleted.
|
||||
*/
|
||||
void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
|
||||
// Check if the service was already removed and if so check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(service->m_removed > 0) {
|
||||
if(deleteSvc) {
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
|
||||
if ((*it) == service) {
|
||||
delete *it;
|
||||
m_svcVec.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = ble_gatts_svc_set_visibility(service->getHandle(), 0);
|
||||
if(rc !=0) {
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
serviceChanged();
|
||||
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a service which was either already created but removed from availability,\n
|
||||
* or created and later added to services list.
|
||||
* @param [in] service The service object to add.
|
||||
* @note If it is desired to advertise the service it must be added by
|
||||
* calling NimBLEAdvertising::addServiceUUID.
|
||||
*/
|
||||
void NimBLEServer::addService(NimBLEService* service) {
|
||||
// Check that a service with the supplied UUID does not already exist.
|
||||
if(getServiceByUUID(service->getUUID()) != nullptr) {
|
||||
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
|
||||
std::string(service->getUUID()).c_str());
|
||||
}
|
||||
|
||||
// If adding a service that was not removed add it and return.
|
||||
// Else reset GATT and send service changed notification.
|
||||
if(service->m_removed == 0) {
|
||||
m_svcVec.push_back(service);
|
||||
return;
|
||||
}
|
||||
|
||||
service->m_removed = 0;
|
||||
serviceChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resets the GATT server, used when services are added/removed after initialization.
|
||||
*/
|
||||
void NimBLEServer::resetGATT() {
|
||||
if(getConnectedCount() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NimBLEDevice::stopAdvertising();
|
||||
ble_gatts_reset();
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = m_svcVec.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
(*it)->start();
|
||||
++it;
|
||||
}
|
||||
|
||||
m_svcChanged = false;
|
||||
m_gattsStarted = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
*
|
||||
* Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
void NimBLEServer::startAdvertising() {
|
||||
NimBLEDevice::startAdvertising();
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop advertising.
|
||||
*/
|
||||
void NimBLEServer::stopAdvertising() {
|
||||
NimBLEDevice::stopAdvertising();
|
||||
} // stopAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the MTU of the client.
|
||||
* @returns The client MTU or 0 if not found/connected.
|
||||
*/
|
||||
uint16_t NimBLEServer::getPeerMTU(uint16_t conn_id) {
|
||||
return ble_att_mtu(conn_id);
|
||||
} //getPeerMTU
|
||||
|
||||
|
||||
/**
|
||||
* @brief Request an Update the connection parameters:
|
||||
* * Can only be used after a connection has been established.
|
||||
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||
* @param [in] minInterval The minimum connection interval in 1.25ms units.
|
||||
* @param [in] maxInterval The maximum connection interval in 1.25ms units.
|
||||
* @param [in] latency The number of packets allowed to skip (extends max interval).
|
||||
* @param [in] timeout The timeout time in 10ms units before disconnecting.
|
||||
*/
|
||||
void NimBLEServer::updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
{
|
||||
ble_gap_upd_params params;
|
||||
|
||||
params.latency = latency;
|
||||
params.itvl_max = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
||||
params.itvl_min = minInterval; // min_int = 0x10*1.25ms = 20ms
|
||||
params.supervision_timeout = timeout; // timeout = 400*10ms = 4000ms
|
||||
params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
||||
params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
||||
|
||||
int rc = ble_gap_update_params(conn_handle, ¶ms);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
} // updateConnParams
|
||||
|
||||
|
||||
/**
|
||||
* @brief Request an update of the data packet length.
|
||||
* * Can only be used after a connection has been established.
|
||||
* @details Sends a data length update request to the peer.
|
||||
* The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
|
||||
* The peer needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
|
||||
* @param [in] conn_handle The connection handle of the peer to send the request to.
|
||||
* @param [in] tx_octets The preferred number of payload octets to use (Range 0x001B-0x00FB).
|
||||
*/
|
||||
void NimBLEServer::setDataLen(uint16_t conn_handle, uint16_t tx_octets) {
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
|
||||
(ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
|
||||
return;
|
||||
#else
|
||||
uint16_t tx_time = (tx_octets + 14) * 8;
|
||||
|
||||
int rc = ble_gap_set_data_len(conn_handle, tx_octets, tx_time);
|
||||
if(rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "Set data length error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
}
|
||||
#endif
|
||||
} // setDataLen
|
||||
|
||||
|
||||
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
|
||||
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
||||
if(m_indWait[i] == conn_handle) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
|
||||
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
|
||||
if(m_indWait[i] == conn_handle) {
|
||||
m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Default callback handlers */
|
||||
|
||||
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
||||
} // onConnect
|
||||
|
||||
|
||||
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConnect(): Default");
|
||||
} // onConnect
|
||||
|
||||
|
||||
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
|
||||
} // onDisconnect
|
||||
|
||||
void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
|
||||
} // onMTUChange
|
||||
|
||||
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
|
||||
return 123456;
|
||||
}
|
||||
/*
|
||||
void NimBLEServerCallbacks::onPassKeyNotify(uint32_t pass_key){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyNotify: default: %d", pass_key);
|
||||
}
|
||||
|
||||
bool NimBLEServerCallbacks::onSecurityRequest(){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onSecurityRequest: default: true");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
void NimBLEServerCallbacks::onAuthenticationComplete(ble_gap_conn_desc*){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onAuthenticationComplete: default");
|
||||
}
|
||||
bool NimBLEServerCallbacks::onConfirmPIN(uint32_t pin){
|
||||
NIMBLE_LOGD("NimBLEServerCallbacks", "onConfirmPIN: default: true");
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
172
lib/NimBLE-Arduino/src/NimBLEServer.h
Normal file
172
lib/NimBLE-Arduino/src/NimBLEServer.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* NimBLEServer.h
|
||||
*
|
||||
* Created: on March 2, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEServer.h
|
||||
*
|
||||
* Created on: Apr 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLESERVER_H_
|
||||
#define MAIN_NIMBLESERVER_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#define NIMBLE_ATT_REMOVE_HIDE 1
|
||||
#define NIMBLE_ATT_REMOVE_DELETE 2
|
||||
|
||||
#define onMtuChanged onMTUChange
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEAddress.h"
|
||||
#include "NimBLEAdvertising.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLESecurity.h"
|
||||
#include "NimBLEConnInfo.h"
|
||||
|
||||
|
||||
class NimBLEService;
|
||||
class NimBLECharacteristic;
|
||||
class NimBLEServerCallbacks;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE server.
|
||||
*/
|
||||
class NimBLEServer {
|
||||
public:
|
||||
size_t getConnectedCount();
|
||||
NimBLEService* createService(const char* uuid);
|
||||
NimBLEService* createService(const NimBLEUUID &uuid);
|
||||
void removeService(NimBLEService* service, bool deleteSvc = false);
|
||||
void addService(NimBLEService* service);
|
||||
NimBLEAdvertising* getAdvertising();
|
||||
void setCallbacks(NimBLEServerCallbacks* pCallbacks,
|
||||
bool deleteCallbacks = true);
|
||||
void startAdvertising();
|
||||
void stopAdvertising();
|
||||
void start();
|
||||
NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
|
||||
NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||
NimBLEService* getServiceByHandle(uint16_t handle);
|
||||
int disconnect(uint16_t connID,
|
||||
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
|
||||
void updateConnParams(uint16_t conn_handle,
|
||||
uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t timeout);
|
||||
void setDataLen(uint16_t conn_handle, uint16_t tx_octets);
|
||||
uint16_t getPeerMTU(uint16_t conn_id);
|
||||
std::vector<uint16_t> getPeerDevices();
|
||||
NimBLEConnInfo getPeerInfo(size_t index);
|
||||
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
|
||||
NimBLEConnInfo getPeerIDInfo(uint16_t id);
|
||||
void advertiseOnDisconnect(bool);
|
||||
|
||||
private:
|
||||
NimBLEServer();
|
||||
~NimBLEServer();
|
||||
friend class NimBLECharacteristic;
|
||||
friend class NimBLEService;
|
||||
friend class NimBLEDevice;
|
||||
friend class NimBLEAdvertising;
|
||||
|
||||
bool m_gattsStarted;
|
||||
bool m_advertiseOnDisconnect;
|
||||
bool m_svcChanged;
|
||||
NimBLEServerCallbacks* m_pServerCallbacks;
|
||||
bool m_deleteCallbacks;
|
||||
uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
|
||||
std::vector<uint16_t> m_connectedPeersVec;
|
||||
|
||||
// uint16_t m_svcChgChrHdl; // Future use
|
||||
|
||||
std::vector<NimBLEService*> m_svcVec;
|
||||
std::vector<NimBLECharacteristic*> m_notifyChrVec;
|
||||
|
||||
static int handleGapEvent(struct ble_gap_event *event, void *arg);
|
||||
void serviceChanged();
|
||||
void resetGATT();
|
||||
bool setIndicateWait(uint16_t conn_handle);
|
||||
void clearIndicateWait(uint16_t conn_handle);
|
||||
}; // NimBLEServer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks associated with the operation of a %BLE server.
|
||||
*/
|
||||
class NimBLEServerCallbacks {
|
||||
public:
|
||||
virtual ~NimBLEServerCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Handle a client connection.
|
||||
* This is called when a client connects.
|
||||
* @param [in] pServer A pointer to the %BLE server that received the client connection.
|
||||
*/
|
||||
virtual void onConnect(NimBLEServer* pServer);
|
||||
|
||||
/**
|
||||
* @brief Handle a client connection.
|
||||
* This is called when a client connects.
|
||||
* @param [in] pServer A pointer to the %BLE server that received the client connection.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection parameters.
|
||||
*/
|
||||
virtual void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Handle a client disconnection.
|
||||
* This is called when a client disconnects.
|
||||
* @param [in] pServer A reference to the %BLE server that received the existing client disconnection.
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer);
|
||||
|
||||
/**
|
||||
* @brief Handle a client disconnection.
|
||||
* This is called when a client discconnects.
|
||||
* @param [in] pServer A pointer to the %BLE server that received the client disconnection.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection.
|
||||
*/
|
||||
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when the connection MTU changes.
|
||||
* @param [in] MTU The new MTU value.
|
||||
* @param [in] desc A pointer to the connection description structure containig information
|
||||
* about the connection.
|
||||
*/
|
||||
virtual void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when a client requests a passkey for pairing.
|
||||
* @return The passkey to be sent to the client.
|
||||
*/
|
||||
virtual uint32_t onPassKeyRequest();
|
||||
|
||||
//virtual void onPassKeyNotify(uint32_t pass_key);
|
||||
//virtual bool onSecurityRequest();
|
||||
|
||||
/**
|
||||
* @brief Called when the pairing procedure is complete.
|
||||
* @param [in] desc A pointer to the struct containing the connection information.\n
|
||||
* This can be used to check the status of the connection encryption/pairing.
|
||||
*/
|
||||
virtual void onAuthenticationComplete(ble_gap_conn_desc* desc);
|
||||
|
||||
/**
|
||||
* @brief Called when using numeric comparision for pairing.
|
||||
* @param [in] pin The pin to compare with the client.
|
||||
* @return True to accept the pin.
|
||||
*/
|
||||
virtual bool onConfirmPIN(uint32_t pin);
|
||||
}; // NimBLEServerCallbacks
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLESERVER_H_ */
|
||||
435
lib/NimBLE-Arduino/src/NimBLEService.cpp
Normal file
435
lib/NimBLE-Arduino/src/NimBLEService.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* NimBLEService.cpp
|
||||
*
|
||||
* Created: on March 2, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEService.cpp
|
||||
*
|
||||
* Created on: Mar 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
// A service is identified by a UUID. A service is also the container for one or more characteristics.
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
#include "NimBLEService.h"
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct an instance of the NimBLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
*/
|
||||
NimBLEService::NimBLEService(const char* uuid)
|
||||
: NimBLEService(NimBLEUUID(uuid)) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct an instance of the BLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
*/
|
||||
NimBLEService::NimBLEService(const NimBLEUUID &uuid) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_pSvcDef = nullptr;
|
||||
m_removed = 0;
|
||||
|
||||
} // NimBLEService
|
||||
|
||||
|
||||
NimBLEService::~NimBLEService() {
|
||||
if(m_pSvcDef != nullptr) {
|
||||
if(m_pSvcDef->characteristics != nullptr) {
|
||||
for(int i=0; m_pSvcDef->characteristics[i].uuid != NULL; ++i) {
|
||||
if(m_pSvcDef->characteristics[i].descriptors) {
|
||||
delete(m_pSvcDef->characteristics[i].descriptors);
|
||||
}
|
||||
}
|
||||
delete(m_pSvcDef->characteristics);
|
||||
}
|
||||
|
||||
delete(m_pSvcDef);
|
||||
}
|
||||
|
||||
for(auto &it : m_chrVec) {
|
||||
delete it;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dump details of this BLE GATT service.
|
||||
* @return N/A.
|
||||
*/
|
||||
void NimBLEService::dump() {
|
||||
NIMBLE_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%2x",
|
||||
m_uuid.toString().c_str(),
|
||||
m_handle);
|
||||
|
||||
std::string res;
|
||||
int count = 0;
|
||||
char hex[5];
|
||||
for (auto &it: m_chrVec) {
|
||||
if (count > 0) {res += "\n";}
|
||||
snprintf(hex, sizeof(hex), "%04x", it->getHandle());
|
||||
count++;
|
||||
res += "handle: 0x";
|
||||
res += hex;
|
||||
res += ", uuid: " + std::string(it->getUUID());
|
||||
}
|
||||
NIMBLE_LOGD(LOG_TAG, "Characteristics:\n%s", res.c_str());
|
||||
} // dump
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the service.
|
||||
* @return the UUID of the service.
|
||||
*/
|
||||
NimBLEUUID NimBLEService::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Builds the database of characteristics/descriptors for the service
|
||||
* and registers it with the NimBLE stack.
|
||||
* @return bool success/failure .
|
||||
*/
|
||||
bool NimBLEService::start() {
|
||||
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
|
||||
|
||||
// Rebuild the service definition if the server attributes have changed.
|
||||
if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
|
||||
if(m_pSvcDef[0].characteristics) {
|
||||
if(m_pSvcDef[0].characteristics[0].descriptors) {
|
||||
delete(m_pSvcDef[0].characteristics[0].descriptors);
|
||||
}
|
||||
delete(m_pSvcDef[0].characteristics);
|
||||
}
|
||||
delete(m_pSvcDef);
|
||||
m_pSvcDef = nullptr;
|
||||
}
|
||||
|
||||
if(m_pSvcDef == nullptr) {
|
||||
// Nimble requires an array of services to be sent to the api
|
||||
// Since we are adding 1 at a time we create an array of 2 and set the type
|
||||
// of the second service to 0 to indicate the end of the array.
|
||||
ble_gatt_svc_def* svc = new ble_gatt_svc_def[2];
|
||||
ble_gatt_chr_def* pChr_a = nullptr;
|
||||
ble_gatt_dsc_def* pDsc_a = nullptr;
|
||||
|
||||
svc[0].type = BLE_GATT_SVC_TYPE_PRIMARY;
|
||||
svc[0].uuid = &m_uuid.getNative()->u;
|
||||
svc[0].includes = NULL;
|
||||
|
||||
int removedCount = 0;
|
||||
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = m_chrVec.erase(it);
|
||||
} else {
|
||||
++removedCount;
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
size_t numChrs = m_chrVec.size() - removedCount;
|
||||
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
|
||||
|
||||
if(!numChrs){
|
||||
svc[0].characteristics = NULL;
|
||||
}else{
|
||||
// Nimble requires the last characteristic to have it's uuid = 0 to indicate the end
|
||||
// of the characteristics for the service. We create 1 extra and set it to null
|
||||
// for this purpose.
|
||||
pChr_a = new ble_gatt_chr_def[numChrs + 1];
|
||||
uint8_t i = 0;
|
||||
for(auto chr_it = m_chrVec.begin(); chr_it != m_chrVec.end(); ++chr_it) {
|
||||
if((*chr_it)->m_removed > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
removedCount = 0;
|
||||
for(auto it = (*chr_it)->m_dscVec.begin(); it != (*chr_it)->m_dscVec.end(); ) {
|
||||
if ((*it)->m_removed > 0) {
|
||||
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
|
||||
delete *it;
|
||||
it = (*chr_it)->m_dscVec.erase(it);
|
||||
} else {
|
||||
++removedCount;
|
||||
++it;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
size_t numDscs = (*chr_it)->m_dscVec.size() - removedCount;
|
||||
|
||||
if(!numDscs){
|
||||
pChr_a[i].descriptors = NULL;
|
||||
} else {
|
||||
// Must have last descriptor uuid = 0 so we have to create 1 extra
|
||||
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
|
||||
uint8_t d = 0;
|
||||
for(auto dsc_it = (*chr_it)->m_dscVec.begin(); dsc_it != (*chr_it)->m_dscVec.end(); ++dsc_it ) {
|
||||
if((*dsc_it)->m_removed > 0) {
|
||||
continue;
|
||||
}
|
||||
pDsc_a[d].uuid = &(*dsc_it)->m_uuid.getNative()->u;
|
||||
pDsc_a[d].att_flags = (*dsc_it)->m_properties;
|
||||
pDsc_a[d].min_key_size = 0;
|
||||
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
|
||||
pDsc_a[d].arg = (*dsc_it);
|
||||
++d;
|
||||
}
|
||||
|
||||
pDsc_a[numDscs].uuid = NULL;
|
||||
pChr_a[i].descriptors = pDsc_a;
|
||||
}
|
||||
|
||||
pChr_a[i].uuid = &(*chr_it)->m_uuid.getNative()->u;
|
||||
pChr_a[i].access_cb = NimBLECharacteristic::handleGapEvent;
|
||||
pChr_a[i].arg = (*chr_it);
|
||||
pChr_a[i].flags = (*chr_it)->m_properties;
|
||||
pChr_a[i].min_key_size = 0;
|
||||
pChr_a[i].val_handle = &(*chr_it)->m_handle;
|
||||
++i;
|
||||
}
|
||||
|
||||
pChr_a[numChrs].uuid = NULL;
|
||||
svc[0].characteristics = pChr_a;
|
||||
}
|
||||
|
||||
// end of services must indicate to api with type = 0
|
||||
svc[1].type = 0;
|
||||
m_pSvcDef = svc;
|
||||
}
|
||||
|
||||
int rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs((const ble_gatt_svc_def*)m_pSvcDef);
|
||||
if (rc != 0) {
|
||||
NIMBLE_LOGE(LOG_TAG, "ble_gatts_add_svcs, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
NIMBLE_LOGD(LOG_TAG, "<< start()");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle associated with this service.
|
||||
* @return The handle associated with this service.
|
||||
*/
|
||||
uint16_t NimBLEService::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint32_t properties, uint16_t max_len) {
|
||||
return createCharacteristic(NimBLEUUID(uuid), properties, max_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @param [in] max_len - The maximum length in bytes that the characteristic value can hold.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties, uint16_t max_len) {
|
||||
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, max_len, this);
|
||||
|
||||
if (getCharacteristic(uuid) != nullptr) {
|
||||
NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
|
||||
std::string(uuid).c_str());
|
||||
}
|
||||
|
||||
addCharacteristic(pCharacteristic);
|
||||
return pCharacteristic;
|
||||
} // createCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a characteristic to the service.
|
||||
* @param[in] pCharacteristic A pointer to the characteristic instance to add to the service.
|
||||
*/
|
||||
void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
|
||||
bool foundRemoved = false;
|
||||
|
||||
if(pCharacteristic->m_removed > 0) {
|
||||
for(auto& it : m_chrVec) {
|
||||
if(it == pCharacteristic) {
|
||||
foundRemoved = true;
|
||||
pCharacteristic->m_removed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundRemoved) {
|
||||
m_chrVec.push_back(pCharacteristic);
|
||||
}
|
||||
|
||||
pCharacteristic->setService(this);
|
||||
getServer()->serviceChanged();
|
||||
} // addCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a characteristic from the service.
|
||||
* @param[in] pCharacteristic A pointer to the characteristic instance to remove from the service.
|
||||
* @param[in] deleteChr If true it will delete the characteristic instance and free it's resources.
|
||||
*/
|
||||
void NimBLEService::removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr) {
|
||||
// Check if the characteristic was already removed and if so, check if this
|
||||
// is being called to delete the object and do so if requested.
|
||||
// Otherwise, ignore the call and return.
|
||||
if(pCharacteristic->m_removed > 0) {
|
||||
if(deleteChr) {
|
||||
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ++it) {
|
||||
if ((*it) == pCharacteristic) {
|
||||
m_chrVec.erase(it);
|
||||
delete *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pCharacteristic->m_removed = deleteChr ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
|
||||
getServer()->serviceChanged();
|
||||
} // removeCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified UUID.
|
||||
* @param [in] uuid The UUID of the characteristic.
|
||||
* @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) {
|
||||
return getCharacteristic(NimBLEUUID(uuid), instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified UUID.
|
||||
* @param [in] uuid The UUID of the characteristic.
|
||||
* @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) {
|
||||
uint16_t position = 0;
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
if (position == instanceId) {
|
||||
return it;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the characteristic object with the specified handle.
|
||||
* @param handle The handle of the characteristic.
|
||||
* @return A pointer to the characteristic object or nullptr if not found.
|
||||
*/
|
||||
NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) {
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getHandle() == handle) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics() {
|
||||
return m_chrVec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics(const char *uuid) {
|
||||
return getCharacteristics(NimBLEUUID(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
|
||||
*/
|
||||
std::vector<NimBLECharacteristic *> NimBLEService::getCharacteristics(const NimBLEUUID &uuid) {
|
||||
std::vector<NimBLECharacteristic*> result;
|
||||
for (auto &it : m_chrVec) {
|
||||
if (it->getUUID() == uuid) {
|
||||
result.push_back(it);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this service.
|
||||
* A service is defined by:
|
||||
* * Its UUID
|
||||
* * Its handle
|
||||
* @return A string representation of this service.
|
||||
*/
|
||||
std::string NimBLEService::toString() {
|
||||
std::string res = "UUID: " + getUUID().toString();
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", getHandle());
|
||||
res += ", handle: 0x";
|
||||
res += hex;
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the BLE server associated with this service.
|
||||
* @return The BLEServer associated with this service.
|
||||
*/
|
||||
NimBLEServer* NimBLEService::getServer() {
|
||||
return NimBLEDevice::getServer();
|
||||
}// getServer
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
87
lib/NimBLE-Arduino/src/NimBLEService.h
Normal file
87
lib/NimBLE-Arduino/src/NimBLEService.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* NimBLEService.h
|
||||
*
|
||||
* Created: on March 2, 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEService.h
|
||||
*
|
||||
* Created on: Mar 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_NIMBLESERVICE_H_
|
||||
#define MAIN_NIMBLESERVICE_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
|
||||
|
||||
#include "NimBLEServer.h"
|
||||
#include "NimBLECharacteristic.h"
|
||||
#include "NimBLEUUID.h"
|
||||
|
||||
|
||||
class NimBLEServer;
|
||||
class NimBLECharacteristic;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE service.
|
||||
*
|
||||
*/
|
||||
class NimBLEService {
|
||||
public:
|
||||
|
||||
NimBLEService(const char* uuid);
|
||||
NimBLEService(const NimBLEUUID &uuid);
|
||||
~NimBLEService();
|
||||
|
||||
NimBLEServer* getServer();
|
||||
|
||||
NimBLEUUID getUUID();
|
||||
uint16_t getHandle();
|
||||
std::string toString();
|
||||
void dump();
|
||||
|
||||
bool start();
|
||||
|
||||
NimBLECharacteristic* createCharacteristic(const char* uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
NimBLECharacteristic* createCharacteristic(const NimBLEUUID &uuid,
|
||||
uint32_t properties =
|
||||
NIMBLE_PROPERTY::READ |
|
||||
NIMBLE_PROPERTY::WRITE,
|
||||
uint16_t max_len = BLE_ATT_ATTR_MAX_LEN);
|
||||
|
||||
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
|
||||
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
|
||||
NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0);
|
||||
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0);
|
||||
NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle);
|
||||
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics();
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics(const char* uuid);
|
||||
std::vector<NimBLECharacteristic*> getCharacteristics(const NimBLEUUID &uuid);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
friend class NimBLEServer;
|
||||
friend class NimBLEDevice;
|
||||
|
||||
uint16_t m_handle;
|
||||
NimBLEUUID m_uuid;
|
||||
ble_gatt_svc_def* m_pSvcDef;
|
||||
uint8_t m_removed;
|
||||
std::vector<NimBLECharacteristic*> m_chrVec;
|
||||
|
||||
}; // NimBLEService
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL */
|
||||
#endif /* MAIN_NIMBLESERVICE_H_ */
|
||||
360
lib/NimBLE-Arduino/src/NimBLEUUID.cpp
Normal file
360
lib/NimBLE-Arduino/src/NimBLEUUID.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* NimBLEUUID.cpp
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEUUID.cpp
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLEUUID.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEUUID";
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from a string.
|
||||
*
|
||||
* Create a UUID from a string. There will be two possible stories here. Either the string represents
|
||||
* a binary data field or the string represents a hex encoding of a UUID.
|
||||
* For the hex encoding, here is an example:
|
||||
*
|
||||
* ```
|
||||
* "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
* 12345678-90ab-cdef-1234-567890abcdef
|
||||
* ```
|
||||
*
|
||||
* This has a length of 36 characters. We need to parse this into 16 bytes.
|
||||
*
|
||||
* @param [in] value The string to build a UUID from.
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(const std::string &value) {
|
||||
m_valueSet = true;
|
||||
if (value.length() == 4) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_16;
|
||||
m_uuid.u16.value = strtoul(value.c_str(), NULL, 16);
|
||||
}
|
||||
else if (value.length() == 8) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_32;
|
||||
m_uuid.u32.value = strtoul(value.c_str(), NULL, 16);
|
||||
}
|
||||
else if (value.length() == 16) {
|
||||
*this = NimBLEUUID((uint8_t*)value.data(), 16, true);
|
||||
}
|
||||
else if (value.length() == 36) {
|
||||
// If the length of the string is 36 bytes then we will assume it is a long hex string in
|
||||
// UUID format.
|
||||
char * position = const_cast<char *>(value.c_str());
|
||||
uint32_t first = strtoul(position, &position, 16);
|
||||
uint16_t second = strtoul(position + 1, &position, 16);
|
||||
uint16_t third = strtoul(position + 1, &position, 16);
|
||||
uint16_t fourth = strtoul(position + 1, &position, 16);
|
||||
uint64_t fifth = strtoull(position + 1, NULL, 16);
|
||||
*this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth);
|
||||
}
|
||||
else {
|
||||
m_valueSet = false;
|
||||
}
|
||||
} // NimBLEUUID(std::string)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from 2, 4, 16 bytes of memory.
|
||||
* @param [in] pData The pointer to the start of the UUID.
|
||||
* @param [in] size The size of the data.
|
||||
* @param [in] msbFirst Is the MSB first in pData memory?
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) {
|
||||
uint8_t *uuidValue = nullptr;
|
||||
|
||||
switch(size) {
|
||||
case 2:
|
||||
uuidValue = (uint8_t*)&m_uuid.u16.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_16;
|
||||
break;
|
||||
case 4:
|
||||
uuidValue = (uint8_t*)&m_uuid.u32.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_32;
|
||||
break;
|
||||
case 16:
|
||||
uuidValue = m_uuid.u128.value;
|
||||
m_uuid.u.type = BLE_UUID_TYPE_128;
|
||||
break;
|
||||
default:
|
||||
m_valueSet = false;
|
||||
NIMBLE_LOGE(LOG_TAG, "Invalid UUID size");
|
||||
return;
|
||||
}
|
||||
if (msbFirst) {
|
||||
std::reverse_copy(pData, pData + size, uuidValue);
|
||||
} else {
|
||||
memcpy(uuidValue, pData, size);
|
||||
}
|
||||
m_valueSet = true;
|
||||
} // NimBLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the 16bit value.
|
||||
* @param [in] uuid The 16bit short form UUID.
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(uint16_t uuid) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_16;
|
||||
m_uuid.u16.value = uuid;
|
||||
m_valueSet = true;
|
||||
} // NimBLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the 32bit value.
|
||||
* @param [in] uuid The 32bit short form UUID.
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(uint32_t uuid) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_32;
|
||||
m_uuid.u32.value = uuid;
|
||||
m_valueSet = true;
|
||||
} // NimBLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the native UUID.
|
||||
* @param [in] uuid The native UUID.
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(const ble_uuid128_t* uuid) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_128;
|
||||
memcpy(m_uuid.u128.value, uuid->value, 16);
|
||||
m_valueSet = true;
|
||||
} // NimBLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the 128bit value using hex parts instead of string,
|
||||
* instead of NimBLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"), it becomes
|
||||
* NimBLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6)
|
||||
*
|
||||
* @param [in] first The first 32bit of the UUID.
|
||||
* @param [in] second The next 16bit of the UUID.
|
||||
* @param [in] third The next 16bit of the UUID.
|
||||
* @param [in] fourth The last 64bit of the UUID, combining the last 2 parts of the string equivalent
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth) {
|
||||
m_uuid.u.type = BLE_UUID_TYPE_128;
|
||||
memcpy(m_uuid.u128.value + 12, &first, 4);
|
||||
memcpy(m_uuid.u128.value + 10, &second, 2);
|
||||
memcpy(m_uuid.u128.value + 8, &third, 2);
|
||||
memcpy(m_uuid.u128.value, &fourth, 8);
|
||||
m_valueSet = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates an empty UUID.
|
||||
*/
|
||||
NimBLEUUID::NimBLEUUID() {
|
||||
m_valueSet = false;
|
||||
} // NimBLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of bits in this uuid.
|
||||
* @return The number of bits in the UUID. One of 16, 32 or 128.
|
||||
*/
|
||||
uint8_t NimBLEUUID::bitSize() const {
|
||||
if (!m_valueSet) return 0;
|
||||
return m_uuid.u.type;
|
||||
} // bitSize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compare a UUID against this UUID.
|
||||
*
|
||||
* @param [in] uuid The UUID to compare against.
|
||||
* @return True if the UUIDs are equal and false otherwise.
|
||||
*/
|
||||
bool NimBLEUUID::equals(const NimBLEUUID &uuid) const {
|
||||
return *this == uuid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a NimBLEUUID from a string of the form:
|
||||
* 0xNNNN
|
||||
* 0xNNNNNNNN
|
||||
* 0x<UUID\>
|
||||
* NNNN
|
||||
* NNNNNNNN
|
||||
* <UUID\>
|
||||
*
|
||||
* @param [in] uuid The string to create the UUID from.
|
||||
*/
|
||||
NimBLEUUID NimBLEUUID::fromString(const std::string &uuid) {
|
||||
uint8_t start = 0;
|
||||
if (strstr(uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters.
|
||||
start = 2;
|
||||
}
|
||||
uint8_t len = uuid.length() - start; // Calculate the length of the string we are going to use.
|
||||
|
||||
if(len == 4) {
|
||||
uint16_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return NimBLEUUID(x);
|
||||
} else if (len == 8) {
|
||||
uint32_t x = strtoul(uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return NimBLEUUID(x);
|
||||
} else if (len == 36) {
|
||||
return NimBLEUUID(uuid);
|
||||
}
|
||||
return NimBLEUUID();
|
||||
} // fromString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the native UUID value.
|
||||
* @return The native UUID value or nullptr if not set.
|
||||
*/
|
||||
const ble_uuid_any_t* NimBLEUUID::getNative() const {
|
||||
if (m_valueSet == false) {
|
||||
NIMBLE_LOGD(LOG_TAG,"<< Return of un-initialized UUID!");
|
||||
return nullptr;
|
||||
}
|
||||
return &m_uuid;
|
||||
} // getNative
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a UUID to its 128 bit representation.
|
||||
* @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
|
||||
* This method will convert 16 or 32bit representations to the full 128bit.
|
||||
* @return The NimBLEUUID converted to 128bit.
|
||||
*/
|
||||
const NimBLEUUID &NimBLEUUID::to128() {
|
||||
// If we either don't have a value or are already a 128 bit UUID, nothing further to do.
|
||||
if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we are 16 bit or 32 bit, then set the other bytes of the UUID.
|
||||
if (m_uuid.u.type == BLE_UUID_TYPE_16) {
|
||||
*this = NimBLEUUID(m_uuid.u16.value, 0x0000, 0x1000, 0x800000805f9b34fb);
|
||||
}
|
||||
else if (m_uuid.u.type == BLE_UUID_TYPE_32) {
|
||||
*this = NimBLEUUID(m_uuid.u32.value, 0x0000, 0x1000, 0x800000805f9b34fb);
|
||||
}
|
||||
|
||||
return *this;
|
||||
} // to128
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert 128 bit UUID to its 16 bit representation.
|
||||
* @details A UUID can be internally represented as 16bit, 32bit or the full 128bit.
|
||||
* This method will convert a 128bit uuid to 16bit if it contains the ble base uuid.
|
||||
* @return The NimBLEUUID converted to 16bit if successful, otherwise the original uuid.
|
||||
*/
|
||||
const NimBLEUUID& NimBLEUUID::to16() {
|
||||
if (!m_valueSet || m_uuid.u.type == BLE_UUID_TYPE_16) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||
uint8_t base128[] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
|
||||
0x00, 0x80, 0x00, 0x10, 0x00, 0x00};
|
||||
if (memcmp(m_uuid.u128.value, base128, sizeof(base128)) == 0 ) {
|
||||
*this = NimBLEUUID(*(uint16_t*)(m_uuid.u128.value + 12));
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a string representation of the UUID.
|
||||
* @details
|
||||
* The format of a string is:
|
||||
* 01234567 8901 2345 6789 012345678901
|
||||
* 0000180d-0000-1000-8000-00805f9b34fb
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
*
|
||||
* @return A string representation of the UUID.
|
||||
* @deprecated Use std::string() operator instead.
|
||||
*/
|
||||
std::string NimBLEUUID::toString() const {
|
||||
return std::string(*this);
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to check if this UUID is equal to another.
|
||||
*/
|
||||
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
|
||||
if(m_valueSet && rhs.m_valueSet) {
|
||||
if(m_uuid.u.type != rhs.m_uuid.u.type) {
|
||||
uint8_t uuidBase[16] = {
|
||||
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
|
||||
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_128){
|
||||
if(rhs.m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u16.value, 2);
|
||||
} else if (rhs.m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &rhs.m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else if(rhs.m_uuid.u.type == BLE_UUID_TYPE_128) {
|
||||
if(m_uuid.u.type == BLE_UUID_TYPE_16){
|
||||
memcpy(uuidBase+12, &m_uuid.u16.value, 2);
|
||||
} else if (m_uuid.u.type == BLE_UUID_TYPE_32){
|
||||
memcpy(uuidBase+12, &m_uuid.u32.value, 4);
|
||||
}
|
||||
return memcmp(rhs.m_uuid.u128.value,uuidBase,16) == 0;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return ble_uuid_cmp(&m_uuid.u, &rhs.m_uuid.u) == 0;
|
||||
}
|
||||
|
||||
return m_valueSet == rhs.m_valueSet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to check if this UUID is not equal to another.
|
||||
*/
|
||||
bool NimBLEUUID::operator !=(const NimBLEUUID & rhs) const {
|
||||
return !this->operator==(rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convienience operator to convert this UUID to string representation.
|
||||
* @details This allows passing NimBLEUUID to functions
|
||||
* that accept std::string and/or or it's methods as a parameter.
|
||||
*/
|
||||
NimBLEUUID::operator std::string() const {
|
||||
if (!m_valueSet) return std::string(); // If we have no value, nothing to format.
|
||||
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
return ble_uuid_to_str(&m_uuid.u, buf);
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
64
lib/NimBLE-Arduino/src/NimBLEUUID.h
Normal file
64
lib/NimBLE-Arduino/src/NimBLEUUID.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* NimBLEUUID.h
|
||||
*
|
||||
* Created: on Jan 24 2020
|
||||
* Author H2zero
|
||||
*
|
||||
* Originally:
|
||||
*
|
||||
* BLEUUID.h
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEUUID_H_
|
||||
#define COMPONENTS_NIMBLEUUID_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_uuid.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_uuid.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE UUID.
|
||||
*/
|
||||
class NimBLEUUID {
|
||||
public:
|
||||
NimBLEUUID(const std::string &uuid);
|
||||
NimBLEUUID(uint16_t uuid);
|
||||
NimBLEUUID(uint32_t uuid);
|
||||
NimBLEUUID(const ble_uuid128_t* uuid);
|
||||
NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst);
|
||||
NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth);
|
||||
NimBLEUUID();
|
||||
|
||||
uint8_t bitSize() const;
|
||||
bool equals(const NimBLEUUID &uuid) const;
|
||||
const ble_uuid_any_t* getNative() const;
|
||||
const NimBLEUUID & to128();
|
||||
const NimBLEUUID& to16();
|
||||
std::string toString() const;
|
||||
static NimBLEUUID fromString(const std::string &uuid);
|
||||
|
||||
bool operator ==(const NimBLEUUID & rhs) const;
|
||||
bool operator !=(const NimBLEUUID & rhs) const;
|
||||
operator std::string() const;
|
||||
|
||||
private:
|
||||
ble_uuid_any_t m_uuid;
|
||||
bool m_valueSet = false;
|
||||
}; // NimBLEUUID
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_NIMBLEUUID_H_ */
|
||||
518
lib/NimBLE-Arduino/src/NimBLEUtils.cpp
Normal file
518
lib/NimBLE-Arduino/src/NimBLEUtils.cpp
Normal file
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* NimBLEUtils.cpp
|
||||
*
|
||||
* Created: on Jan 25 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "NimBLEUtils.h"
|
||||
#include "NimBLELog.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char* LOG_TAG = "NimBLEUtils";
|
||||
|
||||
|
||||
/**
|
||||
* @brief A function for checking validity of connection parameters.
|
||||
* @param [in] params A pointer to the structure containing the parameters to check.
|
||||
* @return valid == 0 or error code.
|
||||
*/
|
||||
int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
|
||||
/* Check connection interval min */
|
||||
if ((params->itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
|
||||
(params->itvl_min > BLE_HCI_CONN_ITVL_MAX)) {
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
/* Check connection interval max */
|
||||
if ((params->itvl_max < BLE_HCI_CONN_ITVL_MIN) ||
|
||||
(params->itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
|
||||
(params->itvl_max < params->itvl_min)) {
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
|
||||
/* Check connection latency */
|
||||
if (params->latency > BLE_HCI_CONN_LATENCY_MAX) {
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
|
||||
/* Check supervision timeout */
|
||||
if ((params->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
|
||||
(params->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
|
||||
/* Check connection event length */
|
||||
if (params->min_ce_len > params->max_ce_len) {
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a return code from the NimBLE stack to a text string.
|
||||
* @param [in] rc The return code to convert.
|
||||
* @return A string representation of the return code.
|
||||
*/
|
||||
const char* NimBLEUtils::returnCodeToString(int rc) {
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||
switch(rc) {
|
||||
case 0:
|
||||
return "SUCCESS";
|
||||
case BLE_HS_EAGAIN:
|
||||
return "Temporary failure; try again.";
|
||||
case BLE_HS_EALREADY:
|
||||
return "Operation already in progress or completed.";
|
||||
case BLE_HS_EINVAL:
|
||||
return "One or more arguments are invalid.";
|
||||
case BLE_HS_EMSGSIZE:
|
||||
return "The provided buffer is too small.";
|
||||
case BLE_HS_ENOENT:
|
||||
return "No entry matching the specified criteria.";
|
||||
case BLE_HS_ENOMEM:
|
||||
return "Operation failed due to resource exhaustion.";
|
||||
case BLE_HS_ENOTCONN:
|
||||
return "No open connection with the specified handle.";
|
||||
case BLE_HS_ENOTSUP:
|
||||
return "Operation disabled at compile time.";
|
||||
case BLE_HS_EAPP:
|
||||
return "Application callback behaved unexpectedly.";
|
||||
case BLE_HS_EBADDATA:
|
||||
return "Command from peer is invalid.";
|
||||
case BLE_HS_EOS:
|
||||
return "Mynewt OS error.";
|
||||
case BLE_HS_ECONTROLLER:
|
||||
return "Event from controller is invalid.";
|
||||
case BLE_HS_ETIMEOUT:
|
||||
return "Operation timed out.";
|
||||
case BLE_HS_EDONE:
|
||||
return "Operation completed successfully.";
|
||||
case BLE_HS_EBUSY:
|
||||
return "Operation cannot be performed until procedure completes.";
|
||||
case BLE_HS_EREJECT:
|
||||
return "Peer rejected a connection parameter update request.";
|
||||
case BLE_HS_EUNKNOWN:
|
||||
return "Unexpected failure; catch all.";
|
||||
case BLE_HS_EROLE:
|
||||
return "Operation requires different role (e.g., central vs. peripheral).";
|
||||
case BLE_HS_ETIMEOUT_HCI:
|
||||
return "HCI request timed out; controller unresponsive.";
|
||||
case BLE_HS_ENOMEM_EVT:
|
||||
return "Controller failed to send event due to memory exhaustion (combined host-controller only).";
|
||||
case BLE_HS_ENOADDR:
|
||||
return "Operation requires an identity address but none configured.";
|
||||
case BLE_HS_ENOTSYNCED:
|
||||
return "Attempt to use the host before it is synced with controller.";
|
||||
case BLE_HS_EAUTHEN:
|
||||
return "Insufficient authentication.";
|
||||
case BLE_HS_EAUTHOR:
|
||||
return "Insufficient authorization.";
|
||||
case BLE_HS_EENCRYPT:
|
||||
return "Insufficient encryption level.";
|
||||
case BLE_HS_EENCRYPT_KEY_SZ:
|
||||
return "Insufficient key size.";
|
||||
case BLE_HS_ESTORE_CAP:
|
||||
return "Storage at capacity.";
|
||||
case BLE_HS_ESTORE_FAIL:
|
||||
return "Storage IO error.";
|
||||
case (0x0100+BLE_ATT_ERR_INVALID_HANDLE ):
|
||||
return "The attribute handle given was not valid on this server.";
|
||||
case (0x0100+BLE_ATT_ERR_READ_NOT_PERMITTED ):
|
||||
return "The attribute cannot be read.";
|
||||
case (0x0100+BLE_ATT_ERR_WRITE_NOT_PERMITTED ):
|
||||
return "The attribute cannot be written.";
|
||||
case (0x0100+BLE_ATT_ERR_INVALID_PDU ):
|
||||
return "The attribute PDU was invalid.";
|
||||
case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHEN ):
|
||||
return "The attribute requires authentication before it can be read or written.";
|
||||
case (0x0100+BLE_ATT_ERR_REQ_NOT_SUPPORTED ):
|
||||
return "Attribute server does not support the request received from the client.";
|
||||
case (0x0100+BLE_ATT_ERR_INVALID_OFFSET ):
|
||||
return "Offset specified was past the end of the attribute.";
|
||||
case (0x0100+BLE_ATT_ERR_INSUFFICIENT_AUTHOR ):
|
||||
return "The attribute requires authorization before it can be read or written.";
|
||||
case (0x0100+BLE_ATT_ERR_PREPARE_QUEUE_FULL ):
|
||||
return "Too many prepare writes have been queued.";
|
||||
case (0x0100+BLE_ATT_ERR_ATTR_NOT_FOUND ):
|
||||
return "No attribute found within the given attribute handle range.";
|
||||
case (0x0100+BLE_ATT_ERR_ATTR_NOT_LONG ):
|
||||
return "The attribute cannot be read or written using the Read Blob Request.";
|
||||
case (0x0100+BLE_ATT_ERR_INSUFFICIENT_KEY_SZ ):
|
||||
return "The Encryption Key Size used for encrypting this link is insufficient.";
|
||||
case (0x0100+BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ):
|
||||
return "The attribute value length is invalid for the operation.";
|
||||
case (0x0100+BLE_ATT_ERR_UNLIKELY ):
|
||||
return "The attribute request has encountered an error that was unlikely, could not be completed as requested.";
|
||||
case (0x0100+BLE_ATT_ERR_INSUFFICIENT_ENC ):
|
||||
return "The attribute requires encryption before it can be read or written.";
|
||||
case (0x0100+BLE_ATT_ERR_UNSUPPORTED_GROUP ):
|
||||
return "The attribute type is not a supported grouping attribute as defined by a higher layer specification.";
|
||||
case (0x0100+BLE_ATT_ERR_INSUFFICIENT_RES ):
|
||||
return "Insufficient Resources to complete the request.";
|
||||
case (0x0200+BLE_ERR_UNKNOWN_HCI_CMD ):
|
||||
return "Unknown HCI Command";
|
||||
case (0x0200+BLE_ERR_UNK_CONN_ID ):
|
||||
return "Unknown Connection Identifier";
|
||||
case (0x0200+BLE_ERR_HW_FAIL ):
|
||||
return "Hardware Failure";
|
||||
case (0x0200+BLE_ERR_PAGE_TMO ):
|
||||
return "Page Timeout";
|
||||
case (0x0200+BLE_ERR_AUTH_FAIL ):
|
||||
return "Authentication Failure";
|
||||
case (0x0200+BLE_ERR_PINKEY_MISSING ):
|
||||
return "PIN or Key Missing";
|
||||
case (0x0200+BLE_ERR_MEM_CAPACITY ):
|
||||
return "Memory Capacity Exceeded";
|
||||
case (0x0200+BLE_ERR_CONN_SPVN_TMO ):
|
||||
return "Connection Timeout";
|
||||
case (0x0200+BLE_ERR_CONN_LIMIT ):
|
||||
return "Connection Limit Exceeded";
|
||||
case (0x0200+BLE_ERR_SYNCH_CONN_LIMIT ):
|
||||
return "Synchronous Connection Limit To A Device Exceeded";
|
||||
case (0x0200+BLE_ERR_ACL_CONN_EXISTS ):
|
||||
return "ACL Connection Already Exists";
|
||||
case (0x0200+BLE_ERR_CMD_DISALLOWED ):
|
||||
return "Command Disallowed";
|
||||
case (0x0200+BLE_ERR_CONN_REJ_RESOURCES ):
|
||||
return "Connection Rejected due to Limited Resources";
|
||||
case (0x0200+BLE_ERR_CONN_REJ_SECURITY ):
|
||||
return "Connection Rejected Due To Security Reasons";
|
||||
case (0x0200+BLE_ERR_CONN_REJ_BD_ADDR ):
|
||||
return "Connection Rejected due to Unacceptable BD_ADDR";
|
||||
case (0x0200+BLE_ERR_CONN_ACCEPT_TMO ):
|
||||
return "Connection Accept Timeout Exceeded";
|
||||
case (0x0200+BLE_ERR_UNSUPPORTED ):
|
||||
return "Unsupported Feature or Parameter Value";
|
||||
case (0x0200+BLE_ERR_INV_HCI_CMD_PARMS ):
|
||||
return "Invalid HCI Command Parameters";
|
||||
case (0x0200+BLE_ERR_REM_USER_CONN_TERM ):
|
||||
return "Remote User Terminated Connection";
|
||||
case (0x0200+BLE_ERR_RD_CONN_TERM_RESRCS ):
|
||||
return "Remote Device Terminated Connection due to Low Resources";
|
||||
case (0x0200+BLE_ERR_RD_CONN_TERM_PWROFF ):
|
||||
return "Remote Device Terminated Connection due to Power Off";
|
||||
case (0x0200+BLE_ERR_CONN_TERM_LOCAL ):
|
||||
return "Connection Terminated By Local Host";
|
||||
case (0x0200+BLE_ERR_REPEATED_ATTEMPTS ):
|
||||
return "Repeated Attempts";
|
||||
case (0x0200+BLE_ERR_NO_PAIRING ):
|
||||
return "Pairing Not Allowed";
|
||||
case (0x0200+BLE_ERR_UNK_LMP ):
|
||||
return "Unknown LMP PDU";
|
||||
case (0x0200+BLE_ERR_UNSUPP_REM_FEATURE ):
|
||||
return "Unsupported Remote Feature / Unsupported LMP Feature";
|
||||
case (0x0200+BLE_ERR_SCO_OFFSET ):
|
||||
return "SCO Offset Rejected";
|
||||
case (0x0200+BLE_ERR_SCO_ITVL ):
|
||||
return "SCO Interval Rejected";
|
||||
case (0x0200+BLE_ERR_SCO_AIR_MODE ):
|
||||
return "SCO Air Mode Rejected";
|
||||
case (0x0200+BLE_ERR_INV_LMP_LL_PARM ):
|
||||
return "Invalid LMP Parameters / Invalid LL Parameters";
|
||||
case (0x0200+BLE_ERR_UNSPECIFIED ):
|
||||
return "Unspecified Error";
|
||||
case (0x0200+BLE_ERR_UNSUPP_LMP_LL_PARM ):
|
||||
return "Unsupported LMP Parameter Value / Unsupported LL Parameter Value";
|
||||
case (0x0200+BLE_ERR_NO_ROLE_CHANGE ):
|
||||
return "Role Change Not Allowed";
|
||||
case (0x0200+BLE_ERR_LMP_LL_RSP_TMO ):
|
||||
return "LMP Response Timeout / LL Response Timeout";
|
||||
case (0x0200+BLE_ERR_LMP_COLLISION ):
|
||||
return "LMP Error Transaction Collision";
|
||||
case (0x0200+BLE_ERR_LMP_PDU ):
|
||||
return "LMP PDU Not Allowed";
|
||||
case (0x0200+BLE_ERR_ENCRYPTION_MODE ):
|
||||
return "Encryption Mode Not Acceptable";
|
||||
case (0x0200+BLE_ERR_LINK_KEY_CHANGE ):
|
||||
return "Link Key cannot be Changed";
|
||||
case (0x0200+BLE_ERR_UNSUPP_QOS ):
|
||||
return "Requested QoS Not Supported";
|
||||
case (0x0200+BLE_ERR_INSTANT_PASSED ):
|
||||
return "Instant Passed";
|
||||
case (0x0200+BLE_ERR_UNIT_KEY_PAIRING ):
|
||||
return "Pairing With Unit Key Not Supported";
|
||||
case (0x0200+BLE_ERR_DIFF_TRANS_COLL ):
|
||||
return "Different Transaction Collision";
|
||||
case (0x0200+BLE_ERR_QOS_PARM ):
|
||||
return "QoS Unacceptable Parameter";
|
||||
case (0x0200+BLE_ERR_QOS_REJECTED ):
|
||||
return "QoS Rejected";
|
||||
case (0x0200+BLE_ERR_CHAN_CLASS ):
|
||||
return "Channel Classification Not Supported";
|
||||
case (0x0200+BLE_ERR_INSUFFICIENT_SEC ):
|
||||
return "Insufficient Security";
|
||||
case (0x0200+BLE_ERR_PARM_OUT_OF_RANGE ):
|
||||
return "Parameter Out Of Mandatory Range";
|
||||
case (0x0200+BLE_ERR_PENDING_ROLE_SW ):
|
||||
return "Role Switch Pending";
|
||||
case (0x0200+BLE_ERR_RESERVED_SLOT ):
|
||||
return "Reserved Slot Violation";
|
||||
case (0x0200+BLE_ERR_ROLE_SW_FAIL ):
|
||||
return "Role Switch Failed";
|
||||
case (0x0200+BLE_ERR_INQ_RSP_TOO_BIG ):
|
||||
return "Extended Inquiry Response Too Large";
|
||||
case (0x0200+BLE_ERR_SEC_SIMPLE_PAIR ):
|
||||
return "Secure Simple Pairing Not Supported By Host";
|
||||
case (0x0200+BLE_ERR_HOST_BUSY_PAIR ):
|
||||
return "Host Busy - Pairing";
|
||||
case (0x0200+BLE_ERR_CONN_REJ_CHANNEL ):
|
||||
return "Connection Rejected, No Suitable Channel Found";
|
||||
case (0x0200+BLE_ERR_CTLR_BUSY ):
|
||||
return "Controller Busy";
|
||||
case (0x0200+BLE_ERR_CONN_PARMS ):
|
||||
return "Unacceptable Connection Parameters";
|
||||
case (0x0200+BLE_ERR_DIR_ADV_TMO ):
|
||||
return "Directed Advertising Timeout";
|
||||
case (0x0200+BLE_ERR_CONN_TERM_MIC ):
|
||||
return "Connection Terminated due to MIC Failure";
|
||||
case (0x0200+BLE_ERR_CONN_ESTABLISHMENT ):
|
||||
return "Connection Failed to be Established";
|
||||
case (0x0200+BLE_ERR_MAC_CONN_FAIL ):
|
||||
return "MAC Connection Failed";
|
||||
case (0x0200+BLE_ERR_COARSE_CLK_ADJ ):
|
||||
return "Coarse Clock Adjustment Rejected";
|
||||
case (0x0300+BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD ):
|
||||
return "Invalid or unsupported incoming L2CAP sig command.";
|
||||
case (0x0300+BLE_L2CAP_SIG_ERR_MTU_EXCEEDED ):
|
||||
return "Incoming packet too large.";
|
||||
case (0x0300+BLE_L2CAP_SIG_ERR_INVALID_CID ):
|
||||
return "No channel with specified ID.";
|
||||
case (0x0400+BLE_SM_ERR_PASSKEY ):
|
||||
return "The user input of passkey failed, for example, the user cancelled the operation.";
|
||||
case (0x0400+BLE_SM_ERR_OOB ):
|
||||
return "The OOB data is not available.";
|
||||
case (0x0400+BLE_SM_ERR_AUTHREQ ):
|
||||
return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices.";
|
||||
case (0x0400+BLE_SM_ERR_CONFIRM_MISMATCH ):
|
||||
return "The confirm value does not match the calculated compare value.";
|
||||
case (0x0400+BLE_SM_ERR_PAIR_NOT_SUPP ):
|
||||
return "Pairing is not supported by the device.";
|
||||
case (0x0400+BLE_SM_ERR_ENC_KEY_SZ ):
|
||||
return "The resultant encryption key size is insufficient for the security requirements of this device.";
|
||||
case (0x0400+BLE_SM_ERR_CMD_NOT_SUPP ):
|
||||
return "The SMP command received is not supported on this device.";
|
||||
case (0x0400+BLE_SM_ERR_UNSPECIFIED ):
|
||||
return "Pairing failed due to an unspecified reason.";
|
||||
case (0x0400+BLE_SM_ERR_REPEATED ):
|
||||
return "Pairing or authentication procedure disallowed, too little time has elapsed since last pairing request or security request.";
|
||||
case (0x0400+BLE_SM_ERR_INVAL ):
|
||||
return "Command length is invalid or that a parameter is outside of the specified range.";
|
||||
case (0x0400+BLE_SM_ERR_DHKEY ):
|
||||
return "DHKey Check value received doesn't match the one calculated by the local device.";
|
||||
case (0x0400+BLE_SM_ERR_NUMCMP ):
|
||||
return "Confirm values in the numeric comparison protocol do not match.";
|
||||
case (0x0400+BLE_SM_ERR_ALREADY ):
|
||||
return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process.";
|
||||
case (0x0400+BLE_SM_ERR_CROSS_TRANS ):
|
||||
return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.";
|
||||
case (0x0500+BLE_SM_ERR_PASSKEY ):
|
||||
return "The user input of passkey failed or the user cancelled the operation.";
|
||||
case (0x0500+BLE_SM_ERR_OOB ):
|
||||
return "The OOB data is not available.";
|
||||
case (0x0500+BLE_SM_ERR_AUTHREQ ):
|
||||
return "The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices.";
|
||||
case (0x0500+BLE_SM_ERR_CONFIRM_MISMATCH ):
|
||||
return "The confirm value does not match the calculated compare value.";
|
||||
case (0x0500+BLE_SM_ERR_PAIR_NOT_SUPP ):
|
||||
return "Pairing is not supported by the device.";
|
||||
case (0x0500+BLE_SM_ERR_ENC_KEY_SZ ):
|
||||
return "The resultant encryption key size is insufficient for the security requirements of this device.";
|
||||
case (0x0500+BLE_SM_ERR_CMD_NOT_SUPP ):
|
||||
return "The SMP command received is not supported on this device.";
|
||||
case (0x0500+BLE_SM_ERR_UNSPECIFIED ):
|
||||
return "Pairing failed due to an unspecified reason.";
|
||||
case (0x0500+BLE_SM_ERR_REPEATED ):
|
||||
return "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request.";
|
||||
case (0x0500+BLE_SM_ERR_INVAL ):
|
||||
return "Command length is invalid or a parameter is outside of the specified range.";
|
||||
case (0x0500+BLE_SM_ERR_DHKEY ):
|
||||
return "Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device.";
|
||||
case (0x0500+BLE_SM_ERR_NUMCMP ):
|
||||
return "Confirm values in the numeric comparison protocol do not match.";
|
||||
case (0x0500+BLE_SM_ERR_ALREADY ):
|
||||
return "Pairing over the LE transport failed - Pairing Request sent over the BR/EDR transport in process.";
|
||||
case (0x0500+BLE_SM_ERR_CROSS_TRANS ):
|
||||
return "BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||
(void)rc;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert the advertising type flag to a string.
|
||||
* @param advType The type to convert.
|
||||
* @return A string representation of the advertising flags.
|
||||
*/
|
||||
const char* NimBLEUtils::advTypeToString(uint8_t advType) {
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
switch(advType) {
|
||||
case BLE_HCI_ADV_TYPE_ADV_IND : //0
|
||||
return "Undirected - Connectable / Scannable";
|
||||
case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: //1
|
||||
return "Directed High Duty - Connectable";
|
||||
case BLE_HCI_ADV_TYPE_ADV_SCAN_IND: //2
|
||||
return "Non-Connectable - Scan Response Available";
|
||||
case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: //3
|
||||
return "Non-Connectable - No Scan Response";
|
||||
case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD: //4
|
||||
return "Directed Low Duty - Connectable";
|
||||
default:
|
||||
return "Unknown flag";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
(void)advType;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT)
|
||||
} // adFlagsToString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a hex representation of data.
|
||||
*
|
||||
* @param [in] target Where to write the hex string. If this is null, we malloc storage.
|
||||
* @param [in] source The start of the binary data.
|
||||
* @param [in] length The length of the data to convert.
|
||||
* @return A pointer to the formatted buffer.
|
||||
*/
|
||||
char* NimBLEUtils::buildHexData(uint8_t* target, const uint8_t* source, uint8_t length) {
|
||||
// Guard against too much data.
|
||||
if (length > 100) length = 100;
|
||||
|
||||
if (target == nullptr) {
|
||||
target = (uint8_t*) malloc(length * 2 + 1);
|
||||
if (target == nullptr) {
|
||||
NIMBLE_LOGE(LOG_TAG, "buildHexData: malloc failed");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
char* startOfData = (char*) target;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
sprintf((char*) target, "%.2x", (char) *source);
|
||||
source++;
|
||||
target += 2;
|
||||
}
|
||||
|
||||
// Handle the special case where there was no data.
|
||||
if (length == 0) {
|
||||
*startOfData = 0;
|
||||
}
|
||||
|
||||
return startOfData;
|
||||
} // buildHexData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility function to log the gap event info.
|
||||
* @param [in] event A pointer to the gap event structure.
|
||||
* @param [in] arg Unused.
|
||||
*/
|
||||
void NimBLEUtils::dumpGapEvent(ble_gap_event *event, void *arg){
|
||||
(void)arg;
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
NIMBLE_LOGD(LOG_TAG, "Received a GAP event: %s", gapEventToString(event->type));
|
||||
#else
|
||||
(void)event;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a GAP event type to a string representation.
|
||||
* @param [in] eventType The type of event.
|
||||
* @return A string representation of the event type.
|
||||
*/
|
||||
const char* NimBLEUtils::gapEventToString(uint8_t eventType) {
|
||||
#if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
switch (eventType) {
|
||||
case BLE_GAP_EVENT_CONNECT : //0
|
||||
return "BLE_GAP_EVENT_CONNECT ";
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT: //1
|
||||
return "BLE_GAP_EVENT_DISCONNECT";
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE: //3
|
||||
return "BLE_GAP_EVENT_CONN_UPDATE";
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE_REQ: //4
|
||||
return "BLE_GAP_EVENT_CONN_UPDATE_REQ";
|
||||
|
||||
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: //5
|
||||
return "BLE_GAP_EVENT_L2CAP_UPDATE_REQ";
|
||||
|
||||
case BLE_GAP_EVENT_TERM_FAILURE: //6
|
||||
return "BLE_GAP_EVENT_TERM_FAILURE";
|
||||
|
||||
case BLE_GAP_EVENT_DISC: //7
|
||||
return "BLE_GAP_EVENT_DISC";
|
||||
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE: //8
|
||||
return "BLE_GAP_EVENT_DISC_COMPLETE";
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE: //9
|
||||
return "BLE_GAP_EVENT_ADV_COMPLETE";
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE: //10
|
||||
return "BLE_GAP_EVENT_ENC_CHANGE";
|
||||
|
||||
case BLE_GAP_EVENT_PASSKEY_ACTION : //11
|
||||
return "BLE_GAP_EVENT_PASSKEY_ACTION";
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_RX: //12
|
||||
return "BLE_GAP_EVENT_NOTIFY_RX";
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX : //13
|
||||
return "BLE_GAP_EVENT_NOTIFY_TX";
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE : //14
|
||||
return "BLE_GAP_EVENT_SUBSCRIBE";
|
||||
|
||||
case BLE_GAP_EVENT_MTU: //15
|
||||
return "BLE_GAP_EVENT_MTU";
|
||||
|
||||
case BLE_GAP_EVENT_IDENTITY_RESOLVED: //16
|
||||
return "BLE_GAP_EVENT_IDENTITY_RESOLVED";
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: //17
|
||||
return "BLE_GAP_EVENT_REPEAT_PAIRING";
|
||||
|
||||
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: //18
|
||||
return "BLE_GAP_EVENT_PHY_UPDATE_COMPLETE";
|
||||
|
||||
case BLE_GAP_EVENT_EXT_DISC: //19
|
||||
return "BLE_GAP_EVENT_EXT_DISC";
|
||||
#ifdef BLE_GAP_EVENT_PERIODIC_SYNC // IDF 4.0 does not support these
|
||||
case BLE_GAP_EVENT_PERIODIC_SYNC: //20
|
||||
return "BLE_GAP_EVENT_PERIODIC_SYNC";
|
||||
|
||||
case BLE_GAP_EVENT_PERIODIC_REPORT: //21
|
||||
return "BLE_GAP_EVENT_PERIODIC_REPORT";
|
||||
|
||||
case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: //22
|
||||
return "BLE_GAP_EVENT_PERIODIC_SYNC_LOST";
|
||||
|
||||
case BLE_GAP_EVENT_SCAN_REQ_RCVD: //23
|
||||
return "BLE_GAP_EVENT_SCAN_REQ_RCVD";
|
||||
#endif
|
||||
default:
|
||||
NIMBLE_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType);
|
||||
return "Unknown event type";
|
||||
}
|
||||
#else // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
(void)eventType;
|
||||
return "";
|
||||
#endif // #if defined(CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT)
|
||||
} // gapEventToString
|
||||
|
||||
#endif //CONFIG_BT_ENABLED
|
||||
51
lib/NimBLE-Arduino/src/NimBLEUtils.h
Normal file
51
lib/NimBLE-Arduino/src/NimBLEUtils.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* NimBLEUtils.h
|
||||
*
|
||||
* Created: on Jan 25 2020
|
||||
* Author H2zero
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_NIMBLEUTILS_H_
|
||||
#define COMPONENTS_NIMBLEUTILS_H_
|
||||
|
||||
#include "nimconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#if defined(CONFIG_NIMBLE_CPP_IDF)
|
||||
#include "host/ble_gap.h"
|
||||
#else
|
||||
#include "nimble/nimble/host/include/host/ble_gap.h"
|
||||
#endif
|
||||
|
||||
/**** FIX COMPILATION ****/
|
||||
#undef min
|
||||
#undef max
|
||||
/**************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef struct {
|
||||
void *pATT;
|
||||
TaskHandle_t task;
|
||||
int rc;
|
||||
void *buf;
|
||||
} ble_task_data_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A BLE Utility class with methods for debugging and general purpose use.
|
||||
*/
|
||||
class NimBLEUtils {
|
||||
public:
|
||||
static void dumpGapEvent(ble_gap_event *event, void *arg);
|
||||
static const char* gapEventToString(uint8_t eventType);
|
||||
static char* buildHexData(uint8_t* target, const uint8_t* source, uint8_t length);
|
||||
static const char* advTypeToString(uint8_t advType);
|
||||
static const char* returnCodeToString(int rc);
|
||||
static int checkConnParams(ble_gap_conn_params* params);
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // COMPONENTS_NIMBLEUTILS_H_
|
||||
267
lib/NimBLE-Arduino/src/nimble/CODING_STANDARDS.md
Normal file
267
lib/NimBLE-Arduino/src/nimble/CODING_STANDARDS.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Coding Style for Apache NimBLE
|
||||
|
||||
Apache NimBLE project is part of Apache Mynewt projct and follows its coding
|
||||
style.
|
||||
|
||||
# Coding Style for Apache Mynewt Core
|
||||
|
||||
This document is meant to define the coding style for Apache Mynewt, and
|
||||
all subprojects of Apache Mynewt. This covers C and Assembly coding
|
||||
conventions, *only*. Other languages (such as Go), have their own
|
||||
coding conventions.
|
||||
|
||||
## Headers
|
||||
|
||||
* All files that are newly written, should have the Apache License clause
|
||||
at the top of them.
|
||||
|
||||
* For files that are copied from another source, but contain an Apache
|
||||
compatible license, the original license header shall be maintained.
|
||||
|
||||
* For more information on applying the Apache license, the definitive
|
||||
source is here: http://www.apache.org/dev/apply-license.html
|
||||
|
||||
* The Apache License clause for the top of files is as follows:
|
||||
|
||||
```no-highlight
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
```
|
||||
|
||||
## Whitespace and Braces
|
||||
|
||||
* Code must be indented to 4 spaces, tabs should not be used.
|
||||
|
||||
* Do not add whitespace at the end of a line.
|
||||
|
||||
* Put space after keywords (for, if, return, switch, while).
|
||||
|
||||
* for, else, if, while statements must have braces around their
|
||||
code blocks, i.e., do:
|
||||
|
||||
```
|
||||
if (x) {
|
||||
assert(0);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
if (x)
|
||||
assert(0);
|
||||
else
|
||||
assert(0);
|
||||
```
|
||||
|
||||
* Braces for statements must be on the same line as the statement. Good:
|
||||
|
||||
```
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (i == 5) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
for (i = 0; i < 10; i++)
|
||||
{ <-- brace must be on same line as for
|
||||
if (i == 5) {
|
||||
break;
|
||||
} <-- no new line between else
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* After a function declaration, the braces should be on a newline, i.e. do:
|
||||
|
||||
```
|
||||
static void *
|
||||
function(int var1, int var2)
|
||||
{
|
||||
```
|
||||
|
||||
not:
|
||||
|
||||
```
|
||||
static void *
|
||||
function(int var1, int var2) {
|
||||
```
|
||||
|
||||
## Line Length and Wrap
|
||||
|
||||
* Line length should never exceed 79 columns.
|
||||
|
||||
* When you have to wrap a long statement, put the operator at the end of the
|
||||
line. i.e.:
|
||||
|
||||
```
|
||||
if (x &&
|
||||
y == 10 &&
|
||||
b)
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
if (x
|
||||
&& y == 10
|
||||
&& b)
|
||||
```
|
||||
|
||||
## Comments
|
||||
|
||||
* No C++ style comments allowed.
|
||||
|
||||
* When using a single line comment, put it above the line of code that you
|
||||
intend to comment, i.e., do:
|
||||
|
||||
```
|
||||
/* check variable */
|
||||
if (a) {
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
if (a) { /* check variable */
|
||||
```
|
||||
|
||||
|
||||
* All public APIs should be commented with Doxygen style comments describing
|
||||
purpose, parameters and return values. Private APIs need not be documented.
|
||||
|
||||
|
||||
## Header files
|
||||
|
||||
* Header files must contain the following structure:
|
||||
* Apache License (see above)
|
||||
* ```#ifdef``` aliasing, to prevent multiple includes
|
||||
* ```#include``` directives for other required header files
|
||||
* ```#ifdef __cplusplus``` wrappers to maintain C++ friendly APIs
|
||||
* Contents of the header file
|
||||
|
||||
* ```#ifdef``` aliasing, shall be in the following format, where
|
||||
the package name is "os" and the file name is "callout.h":
|
||||
|
||||
```no-highlight
|
||||
#ifndef _OS_CALLOUT_H
|
||||
#define _OS_CALLOUT_H
|
||||
```
|
||||
|
||||
* ```#include``` directives must happen prior to the cplusplus
|
||||
wrapper.
|
||||
|
||||
* The cplusplus wrapper must have the following format, and precedes
|
||||
any contents of the header file:
|
||||
|
||||
```no-highlight
|
||||
#ifdef __cplusplus
|
||||
#extern "C" {
|
||||
##endif
|
||||
```
|
||||
|
||||
## Naming
|
||||
|
||||
* Names of functions, structures and variables must be in all lowercase.
|
||||
|
||||
* Names should be as short as possible, but no shorter.
|
||||
|
||||
* Globally visible names must be prefixed with the name of the module,
|
||||
followed by the '_' character, i.e.:
|
||||
|
||||
```
|
||||
os_callout_init(&c)
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
callout_init(c)
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
* No spaces after function names when calling a function, i.e, do:
|
||||
|
||||
```
|
||||
rc = function(a)
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
rc = function (a)
|
||||
```
|
||||
|
||||
|
||||
* Arguments to function calls should have spaces between the comma, i.e. do:
|
||||
|
||||
```
|
||||
rc = function(a, b)
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
rc = function(a,b)
|
||||
```
|
||||
|
||||
* The function type must be on a line by itself preceding the function, i.e. do:
|
||||
|
||||
```
|
||||
static void *
|
||||
function(int var1, int var2)
|
||||
{
|
||||
```
|
||||
|
||||
Not:
|
||||
|
||||
```
|
||||
static void *function(int var1, int var2)
|
||||
{
|
||||
```
|
||||
|
||||
* In general, for functions that return values that denote success or error, 0
|
||||
shall be success, and non-zero shall be the failure code.
|
||||
|
||||
## Variables and Macros
|
||||
|
||||
* Do not use typedefs for structures. This makes it impossible for
|
||||
applications to use pointers to those structures opaquely.
|
||||
|
||||
* typedef may be used for non-structure types, where it is beneficial to
|
||||
hide or alias the underlying type used (e.g. ```os_time_t```.) Indicate
|
||||
typedefs by applying the ```_t``` marker to them.
|
||||
|
||||
* Place all function-local variable definitions at the top of the function body, before any statements.
|
||||
|
||||
## Compiler Directives
|
||||
|
||||
* Code must compile cleanly with -Wall enabled.
|
||||
|
||||
217
lib/NimBLE-Arduino/src/nimble/LICENSE
Normal file
217
lib/NimBLE-Arduino/src/nimble/LICENSE
Normal file
@@ -0,0 +1,217 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
This product bundles queue.h 8.5, which is available under the "3-clause BSD"
|
||||
license. For details, see porting/nimble/include/os/queue.h
|
||||
|
||||
This product partly derives from FreeBSD, which is available under the
|
||||
"3-clause BSD" license. For details, see:
|
||||
* porting/nimble/src/os_mbuf.c
|
||||
|
||||
This product bundles Gary S. Brown's CRC32 implementation, which is available
|
||||
under the following license:
|
||||
COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
code or tables extracted from it, as desired without restriction.
|
||||
|
||||
This product bundles tinycrypt, which is available under the "3-clause BSD"
|
||||
license. For details, and bundled files see:
|
||||
* ext/tinycrypt/LICENSE
|
||||
9
lib/NimBLE-Arduino/src/nimble/NOTICE
Normal file
9
lib/NimBLE-Arduino/src/nimble/NOTICE
Normal file
@@ -0,0 +1,9 @@
|
||||
Apache Mynewt NimBLE
|
||||
Copyright 2015-2020 The Apache Software Foundation
|
||||
Modifications Copyright 2017-2020 Espressif Systems (Shanghai) CO., LTD.
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
Portions of this software were developed at
|
||||
Runtime Inc, copyright 2015.
|
||||
169
lib/NimBLE-Arduino/src/nimble/README.md
Normal file
169
lib/NimBLE-Arduino/src/nimble/README.md
Normal file
@@ -0,0 +1,169 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
|
||||
<img src="http://mynewt.apache.org/img/logo.svg" width="250" alt="Apache Mynewt">
|
||||
|
||||
## Overview
|
||||
|
||||
Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller)
|
||||
that completely replaces the proprietary SoftDevice on Nordic chipsets. It is
|
||||
part of [Apache Mynewt project](https://github.com/apache/mynewt-core).
|
||||
|
||||
Features highlight:
|
||||
- Support for 251 byte packet size
|
||||
- Support for all 4 roles concurrently - Broadcaster, Observer, Peripheral and Central
|
||||
- Support for up to 32 simultaneous connections.
|
||||
- Legacy and SC (secure connections) SMP support (pairing and bonding).
|
||||
- Advertising Extensions.
|
||||
- Coded (aka Long Range) and 2M PHYs.
|
||||
- Bluetooth Mesh.
|
||||
|
||||
## Supported hardware
|
||||
|
||||
Controller supports Nordic nRF51 and nRF52 chipsets. Host runs on any board
|
||||
and architecture [supported](https://github.com/apache/mynewt-core#overview)
|
||||
by Apache Mynewt OS.
|
||||
|
||||
|
||||
## Browsing
|
||||
|
||||
If you are browsing around the source tree, and want to see some of the
|
||||
major functional chunks, here are a few pointers:
|
||||
|
||||
- nimble/controller: Contains code for controller including Link Layer and HCI implementation
|
||||
([controller](https://github.com/apache/mynewt-nimble/tree/master/nimble/controller))
|
||||
|
||||
- nimble/drivers: Contains drivers for supported radio transceivers (Nordic nRF51 and nRF52)
|
||||
([drivers](https://github.com/apache/mynewt-nimble/tree/master/nimble/drivers))
|
||||
|
||||
- nimble/host: Contains code for host subsystem. This includes protocols like
|
||||
L2CAP and ATT, support for HCI commands and events, Generic Access Profile (GAP),
|
||||
Generic Attribute Profile (GATT) and Security Manager (SM).
|
||||
([host](https://github.com/apache/mynewt-nimble/tree/master/nimble/host))
|
||||
|
||||
- nimble/host/mesh: Contains code for Bluetooth Mesh subsystem.
|
||||
([mesh](https://github.com/apache/mynewt-nimble/tree/master/nimble/host/mesh))
|
||||
|
||||
- nimble/transport: Contains code for supported transport protocols between host
|
||||
and controller. This includes UART, emSPI and RAM (used in combined build when
|
||||
host and controller run on same CPU)
|
||||
([transport](https://github.com/apache/mynewt-nimble/tree/master/nimble/transport))
|
||||
|
||||
- porting: Contains implementation of NimBLE Porting Layer (NPL) for supported
|
||||
operating systems
|
||||
([porting](https://github.com/apache/mynewt-nimble/tree/master/porting))
|
||||
|
||||
- ext: Contains external libraries used by NimBLE. Those are used if not
|
||||
provided by OS
|
||||
([ext](https://github.com/apache/mynewt-nimble/tree/master/ext))
|
||||
|
||||
- kernel: Contains the core of the RTOS ([kernel/os](https://github.com/apache/mynewt-core/tree/master/kernel/os))
|
||||
|
||||
## Sample Applications
|
||||
|
||||
There are also some sample applications that show how to Apache Mynewt NimBLE
|
||||
stack. These sample applications are located in the `apps/` directory of
|
||||
Apache Mynewt [repo](https://github.com/apache/mynewt-core). Some examples:
|
||||
|
||||
* [blecent](https://github.com/apache/mynewt-nimble/tree/master/apps/blecent):
|
||||
A basic central device with no user interface. This application scans for
|
||||
a peripheral that supports the alert notification service (ANS). Upon
|
||||
discovering such a peripheral, blecent connects and performs a characteristic
|
||||
read, characteristic write, and notification subscription.
|
||||
* [blehci](https://github.com/apache/mynewt-nimble/tree/master/apps/blehci):
|
||||
Implements a BLE controller-only application. A separate host-only
|
||||
implementation, such as Linux's BlueZ, can interface with this application via
|
||||
HCI over UART.
|
||||
* [bleprph](https://github.com/apache/mynewt-nimble/tree/master/apps/bleprph): An
|
||||
implementation of a minimal BLE peripheral.
|
||||
* [btshell](https://github.com/apache/mynewt-nimble/tree/master/apps/btshell): A
|
||||
shell-like application allowing to configure and use most of NimBLE
|
||||
functionality from command line.
|
||||
* [bleuart](https://github.com/apache/mynewt-core/tree/master/apps/bleuart):
|
||||
Implements a simple BLE peripheral that supports the Nordic
|
||||
UART / Serial Port Emulation service
|
||||
(https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v8.x.x/doc/8.0.0/s110/html/a00072.html).
|
||||
|
||||
# Getting Help
|
||||
|
||||
If you are having trouble using or contributing to Apache Mynewt NimBLE, or just
|
||||
want to talk to a human about what you're working on, you can contact us via the
|
||||
[developers mailing list](mailto:dev@mynewt.apache.org).
|
||||
|
||||
Although not a formal channel, you can also find a number of core developers
|
||||
on the #mynewt channel on Freenode IRC or #general channel on [Mynewt Slack](https://mynewt.slack.com/join/shared_invite/enQtNjA1MTg0NzgyNzg3LTcyMmZiOGQzOGMxM2U4ODFmMTIwNjNmYTE5Y2UwYjQwZWIxNTE0MTUzY2JmMTEzOWFjYWZkNGM0YmM4MzAxNWQ)
|
||||
|
||||
Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/faq/answers)
|
||||
for some help troubleshooting first.
|
||||
|
||||
# Contributing
|
||||
|
||||
Anybody who works with Apache Mynewt can be a contributing member of the
|
||||
community that develops and deploys it. The process of releasing an operating
|
||||
system for microcontrollers is never done: and we welcome your contributions
|
||||
to that effort.
|
||||
|
||||
More information can be found at the Community section of the Apache Mynewt
|
||||
website, located [here](https://mynewt.apache.org/community).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Apache Mynewt welcomes pull request via Github. Discussions are done on Github,
|
||||
but depending on the topic, can also be relayed to the official Apache Mynewt
|
||||
developer mailing list dev@mynewt.apache.org.
|
||||
|
||||
If you are suggesting a new feature, please email the developer list directly,
|
||||
with a description of the feature you are planning to work on.
|
||||
|
||||
## Filing Bugs
|
||||
|
||||
Bugs can be filed on the
|
||||
[Apache Mynewt NimBLE Issues](https://github.com/apache/mynewt-nimble/issues).
|
||||
Please label the issue as a "Bug".
|
||||
|
||||
Where possible, please include a self-contained reproduction case!
|
||||
|
||||
## Feature Requests
|
||||
|
||||
Feature requests should also be filed on the
|
||||
[Apache Mynewt NimBLE Bug Tracker](https://github.com/apache/mynewt-nimble/issues).
|
||||
Please label the issue as a "Feature" or "Enhancement" depending on the scope.
|
||||
|
||||
## Writing Tests
|
||||
|
||||
We love getting newt tests! Apache Mynewt is a huge undertaking, and improving
|
||||
code coverage is a win for every Apache Mynewt user.
|
||||
|
||||
<!--
|
||||
TODO
|
||||
## Writing Documentation
|
||||
|
||||
Contributing to documentation (in addition to writing tests), is a great way
|
||||
to get involved with the Apache Mynewt project.
|
||||
|
||||
The Mynewt NimBLE documentation is found in [/docs](/docs).
|
||||
-->
|
||||
|
||||
# License
|
||||
|
||||
The code in this repository is all under either the Apache 2 license, or a
|
||||
license compatible with the Apache 2 license. See the LICENSE file for more
|
||||
information.
|
||||
33
lib/NimBLE-Arduino/src/nimble/RELEASE_NOTES.md
Normal file
33
lib/NimBLE-Arduino/src/nimble/RELEASE_NOTES.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# RELEASE NOTES
|
||||
|
||||
18 March 2020 - Apache NimBLE v1.3.0
|
||||
|
||||
For full release notes, please visit the
|
||||
[Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes).
|
||||
|
||||
Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) that completely
|
||||
replaces the proprietary SoftDevice on Nordic chipsets.
|
||||
|
||||
New features in this version of NimBLE include:
|
||||
|
||||
* Support for Bluetooth Core Specification 5.1
|
||||
* New blestress test application
|
||||
* Dialog DA1469x CMAC driver
|
||||
* Support for LE Secure Connections out-of-band (OOB) association model
|
||||
* Support for automated generation of syscfg for ports
|
||||
* Qualification related bugfixes
|
||||
* BLE Mesh improvements - fixes and resync with latest Zephyr code
|
||||
* RIOT OS port fixes and improvements
|
||||
* btshell sample application improvements
|
||||
* improvements for bttester application
|
||||
* Controller duplicates filtering improvements
|
||||
* Multi PHY support improvements
|
||||
* Memory and CPU usage optimizations
|
||||
* Use of packed structs for HCI (code size reduction)
|
||||
* Linux sample improvements
|
||||
* PTS test instructions updates
|
||||
* Clock managements improvements in controller
|
||||
|
||||
If working on next-generation RTOS and Bluetooth protocol stack
|
||||
sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt
|
||||
Developer's list, dev@mynewt.apache.org.
|
||||
16
lib/NimBLE-Arduino/src/nimble/console/console.h
Normal file
16
lib/NimBLE-Arduino/src/nimble/console/console.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __CONSOLE_H__
|
||||
#define __CONSOLE_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define console_printf printf
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CONSOLE_H__ */
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef __ESP_COMPILER_H
|
||||
#define __ESP_COMPILER_H
|
||||
|
||||
/*
|
||||
* The likely and unlikely macro pairs:
|
||||
* These macros are useful to place when application
|
||||
* knows the majority ocurrence of a decision paths,
|
||||
* placing one of these macros can hint the compiler
|
||||
* to reorder instructions producing more optimized
|
||||
* code.
|
||||
*/
|
||||
#if (CONFIG_COMPILER_OPTIMIZATION_PERF)
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#endif
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(x) (x)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Utility macros used for designated initializers, which work differently
|
||||
* in C99 and C++ standards mainly for aggregate types.
|
||||
* The member separator, comma, is already part of the macro, please omit the trailing comma.
|
||||
* Usage example:
|
||||
* struct config_t { char* pchr; char arr[SIZE]; } config = {
|
||||
* ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(pchr)
|
||||
* ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(arr, "Value")
|
||||
* };
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) { .member = value },
|
||||
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member) .member = { },
|
||||
#else
|
||||
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) .member = value,
|
||||
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#ifndef __ESP_NIMBLE_HCI_H__
|
||||
#define __ESP_NIMBLE_HCI_H__
|
||||
|
||||
#include "nimble/nimble/include/nimble/ble_hci_trans.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLE_HCI_UART_H4_NONE 0x00
|
||||
#define BLE_HCI_UART_H4_CMD 0x01
|
||||
#define BLE_HCI_UART_H4_ACL 0x02
|
||||
#define BLE_HCI_UART_H4_SCO 0x03
|
||||
#define BLE_HCI_UART_H4_EVT 0x04
|
||||
|
||||
/**
|
||||
* @brief Initialize VHCI transport layer between NimBLE Host and
|
||||
* ESP Bluetooth controller
|
||||
*
|
||||
* This function initializes the transport buffers to be exchanged
|
||||
* between NimBLE host and ESP controller. It also registers required
|
||||
* host callbacks with the controller.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the initialization is successful
|
||||
* - Appropriate error code from esp_err_t in case of an error
|
||||
*/
|
||||
esp_err_t esp_nimble_hci_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize ESP Bluetooth controller(link layer) and VHCI transport
|
||||
* layer between NimBLE Host and ESP Bluetooth controller
|
||||
*
|
||||
* This function initializes ESP controller in BLE only mode and the
|
||||
* transport buffers to be exchanged between NimBLE host and ESP controller.
|
||||
* It also registers required host callbacks with the controller.
|
||||
*
|
||||
* Below is the sequence of APIs to be called to initialize/enable NimBLE host and ESP controller:
|
||||
*
|
||||
* @code{c}
|
||||
* void ble_host_task(void *param)
|
||||
* {
|
||||
* nimble_port_run(); //This function will return only when nimble_port_stop() is executed.
|
||||
* nimble_port_freertos_deinit();
|
||||
* }
|
||||
*
|
||||
* int ret = esp_nimble_hci_and_controller_init();
|
||||
* if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_nimble_hci_and_controller_init() failed with error: %d", ret);
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* nimble_port_init();
|
||||
*
|
||||
* //Initialize the NimBLE Host configuration
|
||||
*
|
||||
* nimble_port_freertos_init(ble_host_task);
|
||||
* @endcode
|
||||
*
|
||||
* nimble_port_freertos_init() is an optional call that creates a new task in which the NimBLE
|
||||
* host will run. The task function should have a call to nimble_port_run(). If a separate task
|
||||
* is not required, calling nimble_port_run() will run the NimBLE host in the current task.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the initialization is successful
|
||||
* - Appropriate error code from esp_err_t in case of an error
|
||||
*/
|
||||
esp_err_t esp_nimble_hci_and_controller_init(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize VHCI transport layer between NimBLE Host and
|
||||
* ESP Bluetooth controller
|
||||
*
|
||||
* @note This function should be called after the NimBLE host is deinitialized.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the deinitialization is successful
|
||||
* - Appropriate error codes from esp_err_t in case of an error
|
||||
*/
|
||||
esp_err_t esp_nimble_hci_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize VHCI transport layer between NimBLE Host and
|
||||
* ESP Bluetooth controller and disable and deinitialize the controller
|
||||
*
|
||||
* @note This function should not be executed in the context of Bluetooth host task.
|
||||
*
|
||||
* @note This function should be called after the NimBLE host is deinitialized.
|
||||
*
|
||||
* Below is the sequence of APIs to be called to disable/deinit NimBLE host and ESP controller:
|
||||
*
|
||||
* @code{c}
|
||||
* int ret = nimble_port_stop();
|
||||
* if (ret == 0) {
|
||||
* nimble_port_deinit();
|
||||
*
|
||||
* ret = esp_nimble_hci_and_controller_deinit();
|
||||
* if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* If nimble_port_freertos_init() is used during initialization, then
|
||||
* nimble_port_freertos_deinit() should be called in the host task after nimble_port_run().
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if the deinitialization is successful
|
||||
* - Appropriate error codes from esp_err_t in case of an error
|
||||
*/
|
||||
esp_err_t esp_nimble_hci_and_controller_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_NIMBLE_HCI_H__ */
|
||||
#endif
|
||||
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include <assert.h>
|
||||
#include "nimble/porting/nimble/include/sysinit/sysinit.h"
|
||||
#include "nimble/nimble/include/nimble/hci_common.h"
|
||||
#include "nimble/nimble/host/include/host/ble_hs.h"
|
||||
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
||||
#include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
|
||||
#include "../include/esp_nimble_hci.h"
|
||||
#include "../../port/include/esp_nimble_mem.h"
|
||||
#include <esp_bt.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "../include/esp_compiler.h"
|
||||
/* IPC is used to improve performance when calls come from a processor not running the NimBLE stack */
|
||||
/* but does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
#include "esp_ipc.h"
|
||||
#endif
|
||||
|
||||
#define NIMBLE_VHCI_TIMEOUT_MS 2000
|
||||
#define BLE_HCI_EVENT_HDR_LEN (2)
|
||||
#define BLE_HCI_CMD_HDR_LEN (3)
|
||||
|
||||
static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb;
|
||||
static void *ble_hci_rx_cmd_hs_arg;
|
||||
|
||||
static ble_hci_trans_rx_acl_fn *ble_hci_rx_acl_hs_cb;
|
||||
static void *ble_hci_rx_acl_hs_arg;
|
||||
|
||||
static struct os_mbuf_pool ble_hci_acl_mbuf_pool;
|
||||
static struct os_mempool_ext ble_hci_acl_pool;
|
||||
/*
|
||||
* The MBUF payload size must accommodate the HCI data header size plus the
|
||||
* maximum ACL data packet length. The ACL block size is the size of the
|
||||
* mbufs we will allocate.
|
||||
*/
|
||||
#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
|
||||
+ BLE_MBUF_MEMBLOCK_OVERHEAD \
|
||||
+ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
|
||||
|
||||
static os_membuf_t *ble_hci_acl_buf;
|
||||
|
||||
static struct os_mempool ble_hci_cmd_pool;
|
||||
static os_membuf_t *ble_hci_cmd_buf;
|
||||
|
||||
static struct os_mempool ble_hci_evt_hi_pool;
|
||||
static os_membuf_t *ble_hci_evt_hi_buf;
|
||||
|
||||
static struct os_mempool ble_hci_evt_lo_pool;
|
||||
static os_membuf_t *ble_hci_evt_lo_buf;
|
||||
|
||||
static SemaphoreHandle_t vhci_send_sem;
|
||||
const static char *TAG = "NimBLE";
|
||||
|
||||
int os_msys_buf_alloc(void);
|
||||
void os_msys_buf_free(void);
|
||||
|
||||
void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
|
||||
void *cmd_arg,
|
||||
ble_hci_trans_rx_acl_fn *acl_cb,
|
||||
void *acl_arg)
|
||||
{
|
||||
ble_hci_rx_cmd_hs_cb = cmd_cb;
|
||||
ble_hci_rx_cmd_hs_arg = cmd_arg;
|
||||
ble_hci_rx_acl_hs_cb = acl_cb;
|
||||
ble_hci_rx_acl_hs_arg = acl_arg;
|
||||
}
|
||||
|
||||
/* Added; Called from the core NimBLE is running on, not used for unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
void ble_hci_trans_hs_cmd_tx_on_core(void *arg)
|
||||
{
|
||||
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
|
||||
esp_vhci_host_send_packet((uint8_t*)arg, *((uint8_t*)arg + 3) + 1 + BLE_HCI_CMD_HDR_LEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modified to use ipc calls in arduino to correct performance issues */
|
||||
int ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
|
||||
{
|
||||
uint16_t len;
|
||||
uint8_t rc = 0;
|
||||
|
||||
assert(cmd != NULL);
|
||||
*cmd = BLE_HCI_UART_H4_CMD;
|
||||
len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1;
|
||||
if (!esp_vhci_host_check_send_available()) {
|
||||
ESP_LOGD(TAG, "Controller not ready to receive packets");
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
|
||||
/* esp_ipc_call_blocking does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
if (xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE && !xPortInIsrContext()) {
|
||||
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
|
||||
ble_hci_trans_hs_cmd_tx_on_core, cmd);
|
||||
} else {
|
||||
esp_vhci_host_send_packet(cmd, len);
|
||||
}
|
||||
#else /* Unicore */
|
||||
esp_vhci_host_send_packet(cmd, len);
|
||||
#endif
|
||||
} else {
|
||||
rc = BLE_HS_ETIMEOUT_HCI;
|
||||
}
|
||||
|
||||
ble_hci_trans_buf_free(cmd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
|
||||
{
|
||||
int rc = ESP_FAIL;
|
||||
|
||||
if (ble_hci_rx_cmd_hs_cb) {
|
||||
rc = ble_hci_rx_cmd_hs_cb(hci_ev, ble_hci_rx_cmd_hs_arg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Added; Called from the core NimBLE is running on, not used for unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
void ble_hci_trans_hs_acl_tx_on_core(void *arg)
|
||||
{
|
||||
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
|
||||
esp_vhci_host_send_packet((uint8_t*)arg + 2, *(uint16_t*)arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modified to use ipc calls in arduino to correct performance issues */
|
||||
int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 3], rc = 0;
|
||||
bool tx_using_nimble_core = 0;
|
||||
/* If this packet is zero length, just free it */
|
||||
if (OS_MBUF_PKTLEN(om) == 0) {
|
||||
os_mbuf_free_chain(om);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!esp_vhci_host_check_send_available()) {
|
||||
ESP_LOGD(TAG, "Controller not ready to receive packets");
|
||||
}
|
||||
|
||||
len = 1 + OS_MBUF_PKTLEN(om);
|
||||
/* Don't check core ID if unicore */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
tx_using_nimble_core = xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE;
|
||||
if (tx_using_nimble_core && !xPortInIsrContext()) {
|
||||
data[0] = len;
|
||||
data[1] = (len >> 8);
|
||||
data[2] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[3]);
|
||||
} else {
|
||||
data[0] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
|
||||
}
|
||||
#else /* Unicore */
|
||||
data[0] = BLE_HCI_UART_H4_ACL;
|
||||
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
|
||||
#endif
|
||||
|
||||
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
|
||||
/* esp_ipc_call_blocking does not exist for solo */
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
if (tx_using_nimble_core && !xPortInIsrContext()) {
|
||||
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
|
||||
ble_hci_trans_hs_acl_tx_on_core, data);
|
||||
} else {
|
||||
esp_vhci_host_send_packet(data, len);
|
||||
}
|
||||
#else /* Unicore */
|
||||
esp_vhci_host_send_packet(data, len);
|
||||
#endif
|
||||
} else {
|
||||
rc = BLE_HS_ETIMEOUT_HCI;
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(om);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
|
||||
{
|
||||
int rc = ESP_FAIL;
|
||||
|
||||
if (ble_hci_rx_acl_hs_cb) {
|
||||
rc = ble_hci_rx_acl_hs_cb(om, ble_hci_rx_acl_hs_arg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
uint8_t *ble_hci_trans_buf_alloc(int type)
|
||||
{
|
||||
uint8_t *buf;
|
||||
|
||||
switch (type) {
|
||||
case BLE_HCI_TRANS_BUF_CMD:
|
||||
buf = os_memblock_get(&ble_hci_cmd_pool);
|
||||
break;
|
||||
|
||||
case BLE_HCI_TRANS_BUF_EVT_HI:
|
||||
buf = os_memblock_get(&ble_hci_evt_hi_pool);
|
||||
if (buf == NULL) {
|
||||
/* If no high-priority event buffers remain, try to grab a
|
||||
* low-priority one.
|
||||
*/
|
||||
buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HCI_TRANS_BUF_EVT_LO:
|
||||
buf = os_memblock_get(&ble_hci_evt_lo_pool);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ble_hci_trans_buf_free(uint8_t *buf)
|
||||
{
|
||||
int rc;
|
||||
/* XXX: this may look a bit odd, but the controller uses the command
|
||||
* buffer to send back the command complete/status as an immediate
|
||||
* response to the command. This was done to insure that the controller
|
||||
* could always send back one of these events when a command was received.
|
||||
* Thus, we check to see which pool the buffer came from so we can free
|
||||
* it to the appropriate pool
|
||||
*/
|
||||
if (os_memblock_from(&ble_hci_evt_hi_pool, buf)) {
|
||||
rc = os_memblock_put(&ble_hci_evt_hi_pool, buf);
|
||||
assert(rc == 0);
|
||||
} else if (os_memblock_from(&ble_hci_evt_lo_pool, buf)) {
|
||||
rc = os_memblock_put(&ble_hci_evt_lo_pool, buf);
|
||||
assert(rc == 0);
|
||||
} else {
|
||||
assert(os_memblock_from(&ble_hci_cmd_pool, buf));
|
||||
rc = os_memblock_put(&ble_hci_cmd_pool, buf);
|
||||
assert(rc == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported; the RAM transport does not have a dedicated ACL data packet
|
||||
* pool.
|
||||
*/
|
||||
int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
|
||||
{
|
||||
ble_hci_acl_pool.mpe_put_cb = cb;
|
||||
ble_hci_acl_pool.mpe_put_arg = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_hci_trans_reset(void)
|
||||
{
|
||||
/* No work to do. All allocated buffers are owned by the host or
|
||||
* controller, and they will get freed by their owners.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a buffer (mbuf) for ACL operation.
|
||||
*
|
||||
* @return The allocated buffer on success;
|
||||
* NULL on buffer exhaustion.
|
||||
*/
|
||||
static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void)
|
||||
{
|
||||
struct os_mbuf *m;
|
||||
uint8_t usrhdr_len;
|
||||
|
||||
#if MYNEWT_VAL(BLE_DEVICE)
|
||||
usrhdr_len = sizeof(struct ble_mbuf_hdr);
|
||||
#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
|
||||
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
|
||||
#else
|
||||
usrhdr_len = 0;
|
||||
#endif
|
||||
|
||||
m = os_mbuf_get_pkthdr(&ble_hci_acl_mbuf_pool, usrhdr_len);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
|
||||
{
|
||||
struct os_mbuf *m;
|
||||
int rc;
|
||||
int sr;
|
||||
if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m = ble_hci_trans_acl_buf_alloc();
|
||||
|
||||
if (!m) {
|
||||
ESP_LOGE(TAG, "%s failed to allocate ACL buffers; increase ACL_BUF_COUNT", __func__);
|
||||
return;
|
||||
}
|
||||
if ((rc = os_mbuf_append(m, data, len)) != 0) {
|
||||
ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc);
|
||||
os_mbuf_free_chain(m);
|
||||
return;
|
||||
}
|
||||
OS_ENTER_CRITICAL(sr);
|
||||
if (ble_hci_rx_acl_hs_cb) {
|
||||
ble_hci_rx_acl_hs_cb(m, NULL);
|
||||
}
|
||||
OS_EXIT_CRITICAL(sr);
|
||||
}
|
||||
|
||||
static void ble_hci_transport_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Ensure this function only gets called by sysinit. */
|
||||
SYSINIT_ASSERT_ACTIVE();
|
||||
|
||||
rc = os_mempool_ext_init(&ble_hci_acl_pool,
|
||||
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
|
||||
ACL_BLOCK_SIZE,
|
||||
ble_hci_acl_buf,
|
||||
"ble_hci_acl_pool");
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = os_mbuf_pool_init(&ble_hci_acl_mbuf_pool,
|
||||
&ble_hci_acl_pool.mpe_mp,
|
||||
ACL_BLOCK_SIZE,
|
||||
MYNEWT_VAL(BLE_ACL_BUF_COUNT));
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
/*
|
||||
* Create memory pool of HCI command buffers. NOTE: we currently dont
|
||||
* allow this to be configured. The controller will only allow one
|
||||
* outstanding command. We decided to keep this a pool in case we allow
|
||||
* allow the controller to handle more than one outstanding command.
|
||||
*/
|
||||
rc = os_mempool_init(&ble_hci_cmd_pool,
|
||||
1,
|
||||
BLE_HCI_TRANS_CMD_SZ,
|
||||
ble_hci_cmd_buf,
|
||||
"ble_hci_cmd_pool");
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = os_mempool_init(&ble_hci_evt_hi_pool,
|
||||
MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
|
||||
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
|
||||
ble_hci_evt_hi_buf,
|
||||
"ble_hci_evt_hi_pool");
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = os_mempool_init(&ble_hci_evt_lo_pool,
|
||||
MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
|
||||
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
|
||||
ble_hci_evt_lo_buf,
|
||||
"ble_hci_evt_lo_pool");
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: BT controller callback function, used to notify the upper layer that
|
||||
* controller is ready to receive command
|
||||
*/
|
||||
static void controller_rcv_pkt_ready(void)
|
||||
{
|
||||
if (vhci_send_sem) {
|
||||
xSemaphoreGive(vhci_send_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: BT controller callback function, to transfer data packet to the host
|
||||
*/
|
||||
static int host_rcv_pkt(uint8_t *data, uint16_t len)
|
||||
{
|
||||
|
||||
if (data[0] == BLE_HCI_UART_H4_EVT) {
|
||||
uint8_t *evbuf;
|
||||
int totlen;
|
||||
int rc;
|
||||
|
||||
totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
|
||||
assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
|
||||
|
||||
if (totlen > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) {
|
||||
ESP_LOGE(TAG, "Received HCI data length at host (%d) exceeds maximum configured HCI event buffer size (%d).",
|
||||
totlen, MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE));
|
||||
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* Allocate LE Advertising Report Event from lo pool only */
|
||||
if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT)) {
|
||||
evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
|
||||
/* Skip advertising report if we're out of memory */
|
||||
if (!evbuf) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
|
||||
assert(evbuf != NULL);
|
||||
}
|
||||
|
||||
memcpy(evbuf, &data[1], totlen);
|
||||
|
||||
rc = ble_hci_trans_ll_evt_tx(evbuf);
|
||||
assert(rc == 0);
|
||||
} else if (data[0] == BLE_HCI_UART_H4_ACL) {
|
||||
ble_hci_rx_acl(data + 1, len - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const esp_vhci_host_callback_t vhci_host_cb = {
|
||||
.notify_host_send_available = controller_rcv_pkt_ready,
|
||||
.notify_host_recv = host_rcv_pkt,
|
||||
};
|
||||
|
||||
static void ble_buf_free(void)
|
||||
{
|
||||
os_msys_buf_free();
|
||||
|
||||
nimble_platform_mem_free(ble_hci_evt_hi_buf);
|
||||
ble_hci_evt_hi_buf = NULL;
|
||||
nimble_platform_mem_free(ble_hci_evt_lo_buf);
|
||||
ble_hci_evt_lo_buf = NULL;
|
||||
nimble_platform_mem_free(ble_hci_cmd_buf);
|
||||
ble_hci_cmd_buf = NULL;
|
||||
nimble_platform_mem_free(ble_hci_acl_buf);
|
||||
ble_hci_acl_buf = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t ble_buf_alloc(void)
|
||||
{
|
||||
if (os_msys_buf_alloc()) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
ble_hci_evt_hi_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
|
||||
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
|
||||
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))));
|
||||
|
||||
ble_hci_evt_lo_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
|
||||
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
|
||||
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))));
|
||||
|
||||
ble_hci_cmd_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
|
||||
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)));
|
||||
|
||||
ble_hci_acl_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
|
||||
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
|
||||
ACL_BLOCK_SIZE)));
|
||||
|
||||
if (!ble_hci_evt_hi_buf || !ble_hci_evt_lo_buf || !ble_hci_cmd_buf || !ble_hci_acl_buf) {
|
||||
ble_buf_free();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_nimble_hci_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ret = ble_buf_alloc();
|
||||
if (ret != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ble_hci_transport_init();
|
||||
|
||||
vhci_send_sem = xSemaphoreCreateBinary();
|
||||
if (vhci_send_sem == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
xSemaphoreGive(vhci_send_sem);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
ble_buf_free();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t esp_nimble_hci_and_controller_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
|
||||
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
return esp_nimble_hci_init();
|
||||
}
|
||||
|
||||
static esp_err_t ble_hci_transport_deinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret += os_mempool_clear(&ble_hci_evt_lo_pool);
|
||||
|
||||
ret += os_mempool_clear(&ble_hci_evt_hi_pool);
|
||||
|
||||
ret += os_mempool_clear(&ble_hci_cmd_pool);
|
||||
|
||||
ret += os_mempool_ext_clear(&ble_hci_acl_pool);
|
||||
|
||||
if (ret) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_nimble_hci_deinit(void)
|
||||
{
|
||||
if (vhci_send_sem) {
|
||||
/* Dummy take & give semaphore before deleting */
|
||||
xSemaphoreTake(vhci_send_sem, portMAX_DELAY);
|
||||
xSemaphoreGive(vhci_send_sem);
|
||||
vSemaphoreDelete(vhci_send_sem);
|
||||
vhci_send_sem = NULL;
|
||||
}
|
||||
esp_err_t ret = ble_hci_transport_deinit();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ble_buf_free();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_nimble_hci_and_controller_deinit(void)
|
||||
{
|
||||
int ret;
|
||||
ret = esp_nimble_hci_deinit();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_disable();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_deinit();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
1385
lib/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_cfg.h
Normal file
1385
lib/NimBLE-Arduino/src/nimble/esp_port/port/include/esp_nimble_cfg.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_NIMBLE_MEM_H__
|
||||
#define __ESP_NIMBLE_MEM_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *nimble_platform_mem_malloc(size_t size);
|
||||
void *nimble_platform_mem_calloc(size_t n, size_t size);
|
||||
void nimble_platform_mem_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_NIMBLE_MEM_H__ */
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "nimconfig.h"
|
||||
#include "../include/esp_nimble_mem.h"
|
||||
|
||||
IRAM_ATTR void *nimble_platform_mem_malloc(size_t size)
|
||||
{
|
||||
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
|
||||
return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
|
||||
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
|
||||
return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
IRAM_ATTR void *nimble_platform_mem_calloc(size_t n, size_t size)
|
||||
{
|
||||
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
|
||||
return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
|
||||
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
|
||||
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
|
||||
return heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||
#else
|
||||
return calloc(n, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
IRAM_ATTR void nimble_platform_mem_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
#endif
|
||||
15
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/AUTHORS
Normal file
15
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/AUTHORS
Normal file
@@ -0,0 +1,15 @@
|
||||
Architect:
|
||||
Rafael Misoczki <rafael.misoczki@intel.com>
|
||||
|
||||
Open Source Maintainer:
|
||||
Constanza Heath <constanza.m.heath@intel.com>
|
||||
Rafael Misoczki <rafael.misoczki@intel.com>
|
||||
|
||||
Contributors:
|
||||
Constanza Heath <constanza.m.heath@intel.com>
|
||||
Rafael Misoczki <rafael.misoczki@intel.com>
|
||||
Flavio Santes <flavio.santes@intel.com>
|
||||
Jarkko Sakkinen <jarkko.sakkinen@intel.com>
|
||||
Chris Morrison
|
||||
Marti Bolivar
|
||||
Colin Ian King
|
||||
61
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/LICENSE
Normal file
61
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/LICENSE
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
================================================================================
|
||||
|
||||
TinyCrypt Cryptographic Library
|
||||
|
||||
================================================================================
|
||||
|
||||
Copyright (c) 2017, Intel Corporation. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
- 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.
|
||||
|
||||
- Neither the name of the Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
================================================================================
|
||||
Copyright (c) 2014, Kenneth MacKay
|
||||
All rights reserved.
|
||||
|
||||
https://github.com/kmackay/micro-ecc
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
|
||||
================================================================================
|
||||
71
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/README
Normal file
71
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/README
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
================================================================================
|
||||
|
||||
TinyCrypt Cryptographic Library
|
||||
|
||||
================================================================================
|
||||
|
||||
Copyright (c) 2017, Intel Corporation. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
- 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.
|
||||
|
||||
- Neither the name of the Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
================================================================================
|
||||
|
||||
Overview:
|
||||
|
||||
The TinyCrypt Library provides an implementation for constrained devices of a
|
||||
minimal set of standard cryptography primitives.
|
||||
|
||||
Please, ***SEE THE DOCUMENTATION*** folder for more information on the supported
|
||||
cryptographic primitives and the limitations of TinyCrypt library. For usage,
|
||||
security and technicalities, please see the corresponding header file of each
|
||||
cryptographic primitive.
|
||||
|
||||
================================================================================
|
||||
|
||||
Organization:
|
||||
|
||||
/lib: C source code of the cryptographic primitives.
|
||||
/lib/include/tinycrypt: C header files of the cryptographic primitives.
|
||||
/tests: Test vectors of the cryptographic primitives.
|
||||
/doc: Documentation of TinyCrypt.
|
||||
|
||||
================================================================================
|
||||
|
||||
Building:
|
||||
|
||||
1) In Makefile.conf set:
|
||||
- CFLAGS for compiler flags.
|
||||
- CC for compiler.
|
||||
- ENABLE_TESTS for enabling (true) or disabling (false) tests compilation.
|
||||
2) In lib/Makefile select the primitives required by your project.
|
||||
3) In tests/Makefile select the corresponding tests of the selected primitives.
|
||||
4) make
|
||||
5) run tests in tests/
|
||||
|
||||
================================================================================
|
||||
|
||||
1
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/VERSION
Normal file
1
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
0.2.8
|
||||
@@ -0,0 +1,352 @@
|
||||
|
||||
TinyCrypt Cryptographic Library
|
||||
###############################
|
||||
Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
|
||||
Overview
|
||||
********
|
||||
The TinyCrypt Library provides an implementation for targeting constrained devices
|
||||
with a minimal set of standard cryptography primitives, as listed below. To better
|
||||
serve applications targeting constrained devices, TinyCrypt implementations differ
|
||||
from the standard specifications (see the Important Remarks section for some
|
||||
important differences). Certain cryptographic primitives depend on other
|
||||
primitives, as mentioned in the list below.
|
||||
|
||||
Aside from the Important Remarks section below, valuable information on the usage,
|
||||
security and technicalities of each cryptographic primitive are found in the
|
||||
corresponding header file.
|
||||
|
||||
* SHA-256:
|
||||
|
||||
* Type of primitive: Hash function.
|
||||
* Standard Specification: NIST FIPS PUB 180-4.
|
||||
* Requires: --
|
||||
|
||||
* HMAC-SHA256:
|
||||
|
||||
* Type of primitive: Message authentication code.
|
||||
* Standard Specification: RFC 2104.
|
||||
* Requires: SHA-256
|
||||
|
||||
* HMAC-PRNG:
|
||||
|
||||
* Type of primitive: Pseudo-random number generator (256-bit strength).
|
||||
* Standard Specification: NIST SP 800-90A.
|
||||
* Requires: SHA-256 and HMAC-SHA256.
|
||||
|
||||
* AES-128:
|
||||
|
||||
* Type of primitive: Block cipher.
|
||||
* Standard Specification: NIST FIPS PUB 197.
|
||||
* Requires: --
|
||||
|
||||
* AES-CBC mode:
|
||||
|
||||
* Type of primitive: Encryption mode of operation.
|
||||
* Standard Specification: NIST SP 800-38A.
|
||||
* Requires: AES-128.
|
||||
|
||||
* AES-CTR mode:
|
||||
|
||||
* Type of primitive: Encryption mode of operation.
|
||||
* Standard Specification: NIST SP 800-38A.
|
||||
* Requires: AES-128.
|
||||
|
||||
* AES-CMAC mode:
|
||||
|
||||
* Type of primitive: Message authentication code.
|
||||
* Standard Specification: NIST SP 800-38B.
|
||||
* Requires: AES-128.
|
||||
|
||||
* AES-CCM mode:
|
||||
|
||||
* Type of primitive: Authenticated encryption.
|
||||
* Standard Specification: NIST SP 800-38C.
|
||||
* Requires: AES-128.
|
||||
|
||||
* CTR-PRNG:
|
||||
|
||||
* Type of primitive: Pseudo-random number generator (128-bit strength).
|
||||
* Standard Specification: NIST SP 800-90A.
|
||||
* Requires: AES-128.
|
||||
|
||||
* ECC-DH:
|
||||
|
||||
* Type of primitive: Key exchange based on curve NIST p-256.
|
||||
* Standard Specification: RFC 6090.
|
||||
* Requires: ECC auxiliary functions (ecc.h/c).
|
||||
|
||||
* ECC-DSA:
|
||||
|
||||
* Type of primitive: Digital signature based on curve NIST p-256.
|
||||
* Standard Specification: RFC 6090.
|
||||
* Requires: ECC auxiliary functions (ecc.h/c).
|
||||
|
||||
Design Goals
|
||||
************
|
||||
|
||||
* Minimize the code size of each cryptographic primitive. This means minimize
|
||||
the size of a platform-independent implementation, as presented in TinyCrypt.
|
||||
Note that various applications may require further features, optimizations with
|
||||
respect to other metrics and countermeasures for particular threats. These
|
||||
peculiarities would increase the code size and thus are not considered here.
|
||||
|
||||
* Minimize the dependencies among the cryptographic primitives. This means
|
||||
that it is unnecessary to build and allocate object code for more primitives
|
||||
than the ones strictly required by the intended application. In other words,
|
||||
one can select and compile only the primitives required by the application.
|
||||
|
||||
|
||||
Important Remarks
|
||||
*****************
|
||||
|
||||
The cryptographic implementations in TinyCrypt library have some limitations.
|
||||
Some of these limitations are inherent to the cryptographic primitives
|
||||
themselves, while others are specific to TinyCrypt. These limitations were accepted
|
||||
in order to meet its design goals (in special, minimal code size) and to better
|
||||
serve applications targeting constrained devices in general. Some of these
|
||||
limitations are discussed in-depth below.
|
||||
|
||||
General Remarks
|
||||
***************
|
||||
|
||||
* TinyCrypt does **not** intend to be fully side-channel resistant. Due to the
|
||||
variety of side-channel attacks, many of them only relevant to certain
|
||||
platforms. In this sense, instead of penalizing all library users with
|
||||
side-channel countermeasures such as increasing the overall code size,
|
||||
TinyCrypt only implements certain generic timing-attack countermeasures.
|
||||
|
||||
Specific Remarks
|
||||
****************
|
||||
|
||||
* SHA-256:
|
||||
|
||||
* The number of bits_hashed in the state is not checked for overflow. Note
|
||||
however that this will only be a problem if you intend to hash more than
|
||||
2^64 bits, which is an extremely large window.
|
||||
|
||||
* HMAC:
|
||||
|
||||
* The HMAC verification process is assumed to be performed by the application.
|
||||
This compares the computed tag with some given tag.
|
||||
Note that conventional memory-comparison methods (such as memcmp function)
|
||||
might be vulnerable to timing attacks; thus be sure to use a constant-time
|
||||
memory comparison function (such as compare_constant_time
|
||||
function provided in lib/utils.c).
|
||||
|
||||
* The tc_hmac_final function, responsible for computing the message tag,
|
||||
cleans the state context before exiting. Thus, applications do not need to
|
||||
clean the TCHmacState_t ctx after calling tc_hmac_final. This should not
|
||||
be changed in future versions of the library as there are applications
|
||||
currently relying on this good-practice/feature of TinyCrypt.
|
||||
|
||||
* HMAC-PRNG:
|
||||
|
||||
* Before using HMAC-PRNG, you *must* find an entropy source to produce a seed.
|
||||
PRNGs only stretch the seed into a seemingly random output of arbitrary
|
||||
length. The security of the output is exactly equal to the
|
||||
unpredictability of the seed.
|
||||
|
||||
* NIST SP 800-90A requires three items as seed material in the initialization
|
||||
step: entropy seed, personalization and a nonce (which is not implemented).
|
||||
TinyCrypt requires the personalization byte array and automatically creates
|
||||
the entropy seed using a mandatory call to the re-seed function.
|
||||
|
||||
* AES-128:
|
||||
|
||||
* The current implementation does not support other key-lengths (such as 256
|
||||
bits). Note that if you need AES-256, it doesn't sound as though your
|
||||
application is running in a constrained environment. AES-256 requires keys
|
||||
twice the size as for AES-128, and the key schedule is 40% larger.
|
||||
|
||||
* CTR mode:
|
||||
|
||||
* The AES-CTR mode limits the size of a data message they encrypt to 2^32
|
||||
blocks. If you need to encrypt larger data sets, your application would
|
||||
need to replace the key after 2^32 block encryptions.
|
||||
|
||||
* CTR-PRNG:
|
||||
|
||||
* Before using CTR-PRNG, you *must* find an entropy source to produce a seed.
|
||||
PRNGs only stretch the seed into a seemingly random output of arbitrary
|
||||
length. The security of the output is exactly equal to the
|
||||
unpredictability of the seed.
|
||||
|
||||
* CBC mode:
|
||||
|
||||
* TinyCrypt CBC decryption assumes that the iv and the ciphertext are
|
||||
contiguous (as produced by TinyCrypt CBC encryption). This allows for a
|
||||
very efficient decryption algorithm that would not otherwise be possible.
|
||||
|
||||
* CMAC mode:
|
||||
|
||||
* AES128-CMAC mode of operation offers 64 bits of security against collision
|
||||
attacks. Note however that an external attacker cannot generate the tags
|
||||
him/herself without knowing the MAC key. In this sense, to attack the
|
||||
collision property of AES128-CMAC, an external attacker would need the
|
||||
cooperation of the legal user to produce an exponentially high number of
|
||||
tags (e.g. 2^64) to finally be able to look for collisions and benefit
|
||||
from them. As an extra precaution, the current implementation allows to at
|
||||
most 2^48 calls to tc_cmac_update function before re-calling tc_cmac_setup
|
||||
(allowing a new key to be set), as suggested in Appendix B of SP 800-38B.
|
||||
|
||||
* CCM mode:
|
||||
|
||||
* There are a few tradeoffs for the selection of the parameters of CCM mode.
|
||||
In special, there is a tradeoff between the maximum number of invocations
|
||||
of CCM under a given key and the maximum payload length for those
|
||||
invocations. Both things are related to the parameter 'q' of CCM mode. The
|
||||
maximum number of invocations of CCM under a given key is determined by
|
||||
the nonce size, which is: 15-q bytes. The maximum payload length for those
|
||||
invocations is defined as 2^(8q) bytes.
|
||||
|
||||
To achieve minimal code size, TinyCrypt CCM implementation fixes q = 2,
|
||||
which is a quite reasonable choice for constrained applications. The
|
||||
implications of this choice are:
|
||||
|
||||
The nonce size is: 13 bytes.
|
||||
|
||||
The maximum payload length is: 2^16 bytes = 65 KB.
|
||||
|
||||
The mac size parameter is an important parameter to estimate the security
|
||||
against collision attacks (that aim at finding different messages that
|
||||
produce the same authentication tag). TinyCrypt CCM implementation
|
||||
accepts any even integer between 4 and 16, as suggested in SP 800-38C.
|
||||
|
||||
* TinyCrypt CCM implementation accepts associated data of any length between
|
||||
0 and (2^16 - 2^8) = 65280 bytes.
|
||||
|
||||
* TinyCrypt CCM implementation accepts:
|
||||
|
||||
* Both non-empty payload and associated data (it encrypts and
|
||||
authenticates the payload and only authenticates the associated data);
|
||||
|
||||
* Non-empty payload and empty associated data (it encrypts and
|
||||
authenticates the payload);
|
||||
|
||||
* Non-empty associated data and empty payload (it degenerates to an
|
||||
authentication-only mode on the associated data).
|
||||
|
||||
* RFC-3610, which also specifies CCM, presents a few relevant security
|
||||
suggestions, such as: it is recommended for most applications to use a
|
||||
mac size greater than 8. Besides, it is emphasized that the usage of the
|
||||
same nonce for two different messages which are encrypted with the same
|
||||
key obviously destroys the security properties of CCM mode.
|
||||
|
||||
* ECC-DH and ECC-DSA:
|
||||
|
||||
* TinyCrypt ECC implementation is based on micro-ecc (see
|
||||
https://github.com/kmackay/micro-ecc). In the original micro-ecc
|
||||
documentation, there is an important remark about the way integers are
|
||||
represented:
|
||||
|
||||
"Integer representation: To reduce code size, all large integers are
|
||||
represented using little-endian words - so the least significant word is
|
||||
first. You can use the 'ecc_bytes2native()' and 'ecc_native2bytes()'
|
||||
functions to convert between the native integer representation and the
|
||||
standardized octet representation."
|
||||
|
||||
Note that the assumed bit layout is: {31, 30, ..., 0}, {63, 62, ..., 32},
|
||||
{95, 94, ..., 64}, {127, 126, ..., 96} for a very-long-integer (vli)
|
||||
consisting of 4 unsigned integers (as an example).
|
||||
|
||||
* A cryptographically-secure PRNG function must be set (using uECC_set_rng())
|
||||
before calling uECC_make_key() or uECC_sign().
|
||||
|
||||
Examples of Applications
|
||||
************************
|
||||
It is possible to do useful cryptography with only the given small set of
|
||||
primitives. With this list of primitives it becomes feasible to support a range
|
||||
of cryptography usages:
|
||||
|
||||
* Measurement of code, data structures, and other digital artifacts (SHA256);
|
||||
|
||||
* Generate commitments (SHA256);
|
||||
|
||||
* Construct keys (HMAC-SHA256);
|
||||
|
||||
* Extract entropy from strings containing some randomness (HMAC-SHA256);
|
||||
|
||||
* Construct random mappings (HMAC-SHA256);
|
||||
|
||||
* Construct nonces and challenges (HMAC-PRNG, CTR-PRNG);
|
||||
|
||||
* Authenticate using a shared secret (HMAC-SHA256);
|
||||
|
||||
* Create an authenticated, replay-protected session (HMAC-SHA256 + HMAC-PRNG);
|
||||
|
||||
* Authenticated encryption (AES-128 + AES-CCM);
|
||||
|
||||
* Key-exchange (EC-DH);
|
||||
|
||||
* Digital signature (EC-DSA);
|
||||
|
||||
Test Vectors
|
||||
************
|
||||
|
||||
The library provides a test program for each cryptographic primitive (see 'test'
|
||||
folder). Besides illustrating how to use the primitives, these tests evaluate
|
||||
the correctness of the implementations by checking the results against
|
||||
well-known publicly validated test vectors.
|
||||
|
||||
For the case of the HMAC-PRNG, due to the necessity of performing an extensive
|
||||
battery test to produce meaningful conclusions, we suggest the user to evaluate
|
||||
the unpredictability of the implementation by using the NIST Statistical Test
|
||||
Suite (see References).
|
||||
|
||||
For the case of the EC-DH and EC-DSA implementations, most of the test vectors
|
||||
were obtained from the site of the NIST Cryptographic Algorithm Validation
|
||||
Program (CAVP), see References.
|
||||
|
||||
References
|
||||
**********
|
||||
|
||||
* `NIST FIPS PUB 180-4 (SHA-256)`_
|
||||
|
||||
.. _NIST FIPS PUB 180-4 (SHA-256):
|
||||
http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
|
||||
|
||||
* `NIST FIPS PUB 197 (AES-128)`_
|
||||
|
||||
.. _NIST FIPS PUB 197 (AES-128):
|
||||
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
|
||||
* `NIST SP800-90A (HMAC-PRNG)`_
|
||||
|
||||
.. _NIST SP800-90A (HMAC-PRNG):
|
||||
http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
|
||||
|
||||
* `NIST SP 800-38A (AES-CBC and AES-CTR)`_
|
||||
|
||||
.. _NIST SP 800-38A (AES-CBC and AES-CTR):
|
||||
http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||
|
||||
* `NIST SP 800-38B (AES-CMAC)`_
|
||||
|
||||
.. _NIST SP 800-38B (AES-CMAC):
|
||||
http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
|
||||
|
||||
* `NIST SP 800-38C (AES-CCM)`_
|
||||
|
||||
.. _NIST SP 800-38C (AES-CCM):
|
||||
http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
|
||||
|
||||
* `NIST Statistical Test Suite (useful for testing HMAC-PRNG)`_
|
||||
|
||||
.. _NIST Statistical Test Suite (useful for testing HMAC-PRNG):
|
||||
http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html
|
||||
|
||||
* `NIST Cryptographic Algorithm Validation Program (CAVP) site`_
|
||||
|
||||
.. _NIST Cryptographic Algorithm Validation Program (CAVP) site:
|
||||
http://csrc.nist.gov/groups/STM/cavp/
|
||||
|
||||
* `RFC 2104 (HMAC-SHA256)`_
|
||||
|
||||
.. _RFC 2104 (HMAC-SHA256):
|
||||
https://www.ietf.org/rfc/rfc2104.txt
|
||||
|
||||
* `RFC 6090 (ECC-DH and ECC-DSA)`_
|
||||
|
||||
.. _RFC 6090 (ECC-DH and ECC-DSA):
|
||||
https://www.ietf.org/rfc/rfc6090.txt
|
||||
@@ -0,0 +1,130 @@
|
||||
/* aes.h - TinyCrypt interface to an AES-128 implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief -- Interface to an AES-128 implementation.
|
||||
*
|
||||
* Overview: AES-128 is a NIST approved block cipher specified in
|
||||
* FIPS 197. Block ciphers are deterministic algorithms that
|
||||
* perform a transformation specified by a symmetric key in fixed-
|
||||
* length data sets, also called blocks.
|
||||
*
|
||||
* Security: AES-128 provides approximately 128 bits of security.
|
||||
*
|
||||
* Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key.
|
||||
*
|
||||
* 2) call tc_aes_encrypt/decrypt to process the data.
|
||||
*/
|
||||
|
||||
#ifndef __TC_AES_H__
|
||||
#define __TC_AES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define Nb (4) /* number of columns (32-bit words) comprising the state */
|
||||
#define Nk (4) /* number of 32-bit words comprising the key */
|
||||
#define Nr (10) /* number of rounds */
|
||||
#define TC_AES_BLOCK_SIZE (Nb*Nk)
|
||||
#define TC_AES_KEY_SIZE (Nb*Nk)
|
||||
|
||||
typedef struct tc_aes_key_sched_struct {
|
||||
unsigned int words[Nb*(Nr+1)];
|
||||
} *TCAesKeySched_t;
|
||||
|
||||
/**
|
||||
* @brief Set AES-128 encryption key
|
||||
* Uses key k to initialize s
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
|
||||
* @note This implementation skips the additional steps required for keys
|
||||
* larger than 128 bits, and must not be used for AES-192 or
|
||||
* AES-256 key schedule -- see FIPS 197 for details
|
||||
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
|
||||
* @param k IN -- points to the AES key
|
||||
*/
|
||||
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k);
|
||||
|
||||
/**
|
||||
* @brief AES-128 Encryption procedure
|
||||
* Encrypts contents of in buffer into out buffer under key;
|
||||
* schedule s
|
||||
* @note Assumes s was initialized by aes_set_encrypt_key;
|
||||
* out and in point to 16 byte buffers
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL
|
||||
* @param out IN/OUT -- buffer to receive ciphertext block
|
||||
* @param in IN -- a plaintext block to encrypt
|
||||
* @param s IN -- initialized AES key schedule
|
||||
*/
|
||||
int tc_aes_encrypt(uint8_t *out, const uint8_t *in,
|
||||
const TCAesKeySched_t s);
|
||||
|
||||
/**
|
||||
* @brief Set the AES-128 decryption key
|
||||
* Uses key k to initialize s
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
|
||||
* @note This is the implementation of the straightforward inverse cipher
|
||||
* using the cipher documented in FIPS-197 figure 12, not the
|
||||
* equivalent inverse cipher presented in Figure 15
|
||||
* @warning This routine skips the additional steps required for keys larger
|
||||
* than 128, and must not be used for AES-192 or AES-256 key
|
||||
* schedule -- see FIPS 197 for details
|
||||
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
|
||||
* @param k IN -- points to the AES key
|
||||
*/
|
||||
int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k);
|
||||
|
||||
/**
|
||||
* @brief AES-128 Encryption procedure
|
||||
* Decrypts in buffer into out buffer under key schedule s
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL
|
||||
* @note Assumes s was initialized by aes_set_encrypt_key
|
||||
* out and in point to 16 byte buffers
|
||||
* @param out IN/OUT -- buffer to receive ciphertext block
|
||||
* @param in IN -- a plaintext block to encrypt
|
||||
* @param s IN -- initialized AES key schedule
|
||||
*/
|
||||
int tc_aes_decrypt(uint8_t *out, const uint8_t *in,
|
||||
const TCAesKeySched_t s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_AES_H__ */
|
||||
@@ -0,0 +1,151 @@
|
||||
/* cbc_mode.h - TinyCrypt interface to a CBC mode implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to a CBC mode implementation.
|
||||
*
|
||||
* Overview: CBC (for "cipher block chaining") mode is a NIST approved mode of
|
||||
* operation defined in SP 800-38a. It can be used with any block
|
||||
* cipher to provide confidentiality of strings whose lengths are
|
||||
* multiples of the block_size of the underlying block cipher.
|
||||
* TinyCrypt hard codes AES as the block cipher.
|
||||
*
|
||||
* Security: CBC mode provides data confidentiality given that the maximum
|
||||
* number q of blocks encrypted under a single key satisfies
|
||||
* q < 2^63, which is not a practical constraint (it is considered a
|
||||
* good practice to replace the encryption when q == 2^56). CBC mode
|
||||
* provides NO data integrity.
|
||||
*
|
||||
* CBC mode assumes that the IV value input into the
|
||||
* tc_cbc_mode_encrypt is randomly generated. The TinyCrypt library
|
||||
* provides HMAC-PRNG module, which generates suitable IVs. Other
|
||||
* methods for generating IVs are acceptable, provided that the
|
||||
* values of the IVs generated appear random to any adversary,
|
||||
* including someone with complete knowledge of the system design.
|
||||
*
|
||||
* The randomness property on which CBC mode's security depends is
|
||||
* the unpredictability of the IV. Since it is unpredictable, this
|
||||
* means in practice that CBC mode requires that the IV is stored
|
||||
* somehow with the ciphertext in order to recover the plaintext.
|
||||
*
|
||||
* TinyCrypt CBC encryption prepends the IV to the ciphertext,
|
||||
* because this affords a more efficient (few buffers) decryption.
|
||||
* Hence tc_cbc_mode_encrypt assumes the ciphertext buffer is always
|
||||
* 16 bytes larger than the plaintext buffer.
|
||||
*
|
||||
* Requires: AES-128
|
||||
*
|
||||
* Usage: 1) call tc_cbc_mode_encrypt to encrypt data.
|
||||
*
|
||||
* 2) call tc_cbc_mode_decrypt to decrypt data.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TC_CBC_MODE_H__
|
||||
#define __TC_CBC_MODE_H__
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief CBC encryption procedure
|
||||
* CBC encrypts inlen bytes of the in buffer into the out buffer
|
||||
* using the encryption key schedule provided, prepends iv to out
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL or
|
||||
* in == NULL or
|
||||
* ctr == NULL or
|
||||
* sched == NULL or
|
||||
* inlen == 0 or
|
||||
* (inlen % TC_AES_BLOCK_SIZE) != 0 or
|
||||
* (outlen % TC_AES_BLOCK_SIZE) != 0 or
|
||||
* outlen != inlen + TC_AES_BLOCK_SIZE
|
||||
* @note Assumes: - sched has been configured by aes_set_encrypt_key
|
||||
* - iv contains a 16 byte random string
|
||||
* - out buffer is large enough to hold the ciphertext + iv
|
||||
* - out buffer is a contiguous buffer
|
||||
* - in holds the plaintext and is a contiguous buffer
|
||||
* - inlen gives the number of bytes in the in buffer
|
||||
* @param out IN/OUT -- buffer to receive the ciphertext
|
||||
* @param outlen IN -- length of ciphertext buffer in bytes
|
||||
* @param in IN -- plaintext to encrypt
|
||||
* @param inlen IN -- length of plaintext buffer in bytes
|
||||
* @param iv IN -- the IV for the this encrypt/decrypt
|
||||
* @param sched IN -- AES key schedule for this encrypt
|
||||
*/
|
||||
int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, const uint8_t *iv,
|
||||
const TCAesKeySched_t sched);
|
||||
|
||||
/**
|
||||
* @brief CBC decryption procedure
|
||||
* CBC decrypts inlen bytes of the in buffer into the out buffer
|
||||
* using the provided encryption key schedule
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL or
|
||||
* in == NULL or
|
||||
* sched == NULL or
|
||||
* inlen == 0 or
|
||||
* outlen == 0 or
|
||||
* (inlen % TC_AES_BLOCK_SIZE) != 0 or
|
||||
* (outlen % TC_AES_BLOCK_SIZE) != 0 or
|
||||
* outlen != inlen + TC_AES_BLOCK_SIZE
|
||||
* @note Assumes:- in == iv + ciphertext, i.e. the iv and the ciphertext are
|
||||
* contiguous. This allows for a very efficient decryption
|
||||
* algorithm that would not otherwise be possible
|
||||
* - sched was configured by aes_set_decrypt_key
|
||||
* - out buffer is large enough to hold the decrypted plaintext
|
||||
* and is a contiguous buffer
|
||||
* - inlen gives the number of bytes in the in buffer
|
||||
* @param out IN/OUT -- buffer to receive decrypted data
|
||||
* @param outlen IN -- length of plaintext buffer in bytes
|
||||
* @param in IN -- ciphertext to decrypt, including IV
|
||||
* @param inlen IN -- length of ciphertext buffer in bytes
|
||||
* @param iv IN -- the IV for the this encrypt/decrypt
|
||||
* @param sched IN -- AES key schedule for this decrypt
|
||||
*
|
||||
*/
|
||||
int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, const uint8_t *iv,
|
||||
const TCAesKeySched_t sched);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CBC_MODE_H__ */
|
||||
@@ -0,0 +1,211 @@
|
||||
/* ccm_mode.h - TinyCrypt interface to a CCM mode implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to a CCM mode implementation.
|
||||
*
|
||||
* Overview: CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of
|
||||
* operation defined in SP 800-38C.
|
||||
*
|
||||
* TinyCrypt CCM implementation accepts:
|
||||
*
|
||||
* 1) Both non-empty payload and associated data (it encrypts and
|
||||
* authenticates the payload and also authenticates the associated
|
||||
* data);
|
||||
* 2) Non-empty payload and empty associated data (it encrypts and
|
||||
* authenticates the payload);
|
||||
* 3) Non-empty associated data and empty payload (it degenerates to
|
||||
* an authentication mode on the associated data).
|
||||
*
|
||||
* TinyCrypt CCM implementation accepts associated data of any length
|
||||
* between 0 and (2^16 - 2^8) bytes.
|
||||
*
|
||||
* Security: The mac length parameter is an important parameter to estimate the
|
||||
* security against collision attacks (that aim at finding different
|
||||
* messages that produce the same authentication tag). TinyCrypt CCM
|
||||
* implementation accepts any even integer between 4 and 16, as
|
||||
* suggested in SP 800-38C.
|
||||
*
|
||||
* RFC-3610, which also specifies CCM, presents a few relevant
|
||||
* security suggestions, such as: it is recommended for most
|
||||
* applications to use a mac length greater than 8. Besides, the
|
||||
* usage of the same nonce for two different messages which are
|
||||
* encrypted with the same key destroys the security of CCM mode.
|
||||
*
|
||||
* Requires: AES-128
|
||||
*
|
||||
* Usage: 1) call tc_ccm_config to configure.
|
||||
*
|
||||
* 2) call tc_ccm_mode_encrypt to encrypt data and generate tag.
|
||||
*
|
||||
* 3) call tc_ccm_mode_decrypt to decrypt data and verify tag.
|
||||
*/
|
||||
|
||||
#ifndef __TC_CCM_MODE_H__
|
||||
#define __TC_CCM_MODE_H__
|
||||
|
||||
#include "aes.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* max additional authenticated size in bytes: 2^16 - 2^8 = 65280 */
|
||||
#define TC_CCM_AAD_MAX_BYTES 0xff00
|
||||
|
||||
/* max message size in bytes: 2^(8L) = 2^16 = 65536 */
|
||||
#define TC_CCM_PAYLOAD_MAX_BYTES 0x10000
|
||||
|
||||
/* struct tc_ccm_mode_struct represents the state of a CCM computation */
|
||||
typedef struct tc_ccm_mode_struct {
|
||||
TCAesKeySched_t sched; /* AES key schedule */
|
||||
uint8_t *nonce; /* nonce required by CCM */
|
||||
unsigned int mlen; /* mac length in bytes (parameter t in SP-800 38C) */
|
||||
} *TCCcmMode_t;
|
||||
|
||||
/**
|
||||
* @brief CCM configuration procedure
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* c == NULL or
|
||||
* sched == NULL or
|
||||
* nonce == NULL or
|
||||
* mlen != {4, 6, 8, 10, 12, 16}
|
||||
* @param c -- CCM state
|
||||
* @param sched IN -- AES key schedule
|
||||
* @param nonce IN - nonce
|
||||
* @param nlen -- nonce length in bytes
|
||||
* @param mlen -- mac length in bytes (parameter t in SP-800 38C)
|
||||
*/
|
||||
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
|
||||
unsigned int nlen, unsigned int mlen);
|
||||
|
||||
/**
|
||||
* @brief CCM tag generation and encryption procedure
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL or
|
||||
* c == NULL or
|
||||
* ((plen > 0) and (payload == NULL)) or
|
||||
* ((alen > 0) and (associated_data == NULL)) or
|
||||
* (alen >= TC_CCM_AAD_MAX_BYTES) or
|
||||
* (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
|
||||
* (olen < plen + maclength)
|
||||
*
|
||||
* @param out OUT -- encrypted data
|
||||
* @param olen IN -- output length in bytes
|
||||
* @param associated_data IN -- associated data
|
||||
* @param alen IN -- associated data length in bytes
|
||||
* @param payload IN -- payload
|
||||
* @param plen IN -- payload length in bytes
|
||||
* @param c IN -- CCM state
|
||||
*
|
||||
* @note: out buffer should be at least (plen + c->mlen) bytes long.
|
||||
*
|
||||
* @note: The sequence b for encryption is formatted as follows:
|
||||
* b = [FLAGS | nonce | counter ], where:
|
||||
* FLAGS is 1 byte long
|
||||
* nonce is 13 bytes long
|
||||
* counter is 2 bytes long
|
||||
* The byte FLAGS is composed by the following 8 bits:
|
||||
* 0-2 bits: used to represent the value of q-1
|
||||
* 3-7 btis: always 0's
|
||||
*
|
||||
* @note: The sequence b for authentication is formatted as follows:
|
||||
* b = [FLAGS | nonce | length(mac length)], where:
|
||||
* FLAGS is 1 byte long
|
||||
* nonce is 13 bytes long
|
||||
* length(mac length) is 2 bytes long
|
||||
* The byte FLAGS is composed by the following 8 bits:
|
||||
* 0-2 bits: used to represent the value of q-1
|
||||
* 3-5 bits: mac length (encoded as: (mlen-2)/2)
|
||||
* 6: Adata (0 if alen == 0, and 1 otherwise)
|
||||
* 7: always 0
|
||||
*/
|
||||
int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
|
||||
const uint8_t *associated_data,
|
||||
unsigned int alen, const uint8_t *payload,
|
||||
unsigned int plen, TCCcmMode_t c);
|
||||
|
||||
/**
|
||||
* @brief CCM decryption and tag verification procedure
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL or
|
||||
* c == NULL or
|
||||
* ((plen > 0) and (payload == NULL)) or
|
||||
* ((alen > 0) and (associated_data == NULL)) or
|
||||
* (alen >= TC_CCM_AAD_MAX_BYTES) or
|
||||
* (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
|
||||
* (olen < plen - c->mlen)
|
||||
*
|
||||
* @param out OUT -- decrypted data
|
||||
* @param associated_data IN -- associated data
|
||||
* @param alen IN -- associated data length in bytes
|
||||
* @param payload IN -- payload
|
||||
* @param plen IN -- payload length in bytes
|
||||
* @param c IN -- CCM state
|
||||
*
|
||||
* @note: out buffer should be at least (plen - c->mlen) bytes long.
|
||||
*
|
||||
* @note: The sequence b for encryption is formatted as follows:
|
||||
* b = [FLAGS | nonce | counter ], where:
|
||||
* FLAGS is 1 byte long
|
||||
* nonce is 13 bytes long
|
||||
* counter is 2 bytes long
|
||||
* The byte FLAGS is composed by the following 8 bits:
|
||||
* 0-2 bits: used to represent the value of q-1
|
||||
* 3-7 btis: always 0's
|
||||
*
|
||||
* @note: The sequence b for authentication is formatted as follows:
|
||||
* b = [FLAGS | nonce | length(mac length)], where:
|
||||
* FLAGS is 1 byte long
|
||||
* nonce is 13 bytes long
|
||||
* length(mac length) is 2 bytes long
|
||||
* The byte FLAGS is composed by the following 8 bits:
|
||||
* 0-2 bits: used to represent the value of q-1
|
||||
* 3-5 bits: mac length (encoded as: (mlen-2)/2)
|
||||
* 6: Adata (0 if alen == 0, and 1 otherwise)
|
||||
* 7: always 0
|
||||
*/
|
||||
int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
|
||||
const uint8_t *associated_data,
|
||||
unsigned int alen, const uint8_t *payload, unsigned int plen,
|
||||
TCCcmMode_t c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CCM_MODE_H__ */
|
||||
@@ -0,0 +1,194 @@
|
||||
/* cmac_mode.h -- interface to a CMAC implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to a CMAC implementation.
|
||||
*
|
||||
* Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm
|
||||
* for computing a MAC using a block cipher. It can compute the MAC
|
||||
* for a byte string of any length. It is distinguished from CBC-MAC
|
||||
* in the processing of the final message block; CMAC uses a
|
||||
* different technique to compute the final message block is full
|
||||
* size or only partial, while CBC-MAC uses the same technique for
|
||||
* both. This difference permits CMAC to be applied to variable
|
||||
* length messages, while all messages authenticated by CBC-MAC must
|
||||
* be the same length.
|
||||
*
|
||||
* Security: AES128-CMAC mode of operation offers 64 bits of security against
|
||||
* collision attacks. Note however that an external attacker cannot
|
||||
* generate the tags him/herself without knowing the MAC key. In this
|
||||
* sense, to attack the collision property of AES128-CMAC, an
|
||||
* external attacker would need the cooperation of the legal user to
|
||||
* produce an exponentially high number of tags (e.g. 2^64) to
|
||||
* finally be able to look for collisions and benefit from them. As
|
||||
* an extra precaution, the current implementation allows to at most
|
||||
* 2^48 calls to the tc_cmac_update function before re-calling
|
||||
* tc_cmac_setup (allowing a new key to be set), as suggested in
|
||||
* Appendix B of SP 800-38B.
|
||||
*
|
||||
* Requires: AES-128
|
||||
*
|
||||
* Usage: This implementation provides a "scatter-gather" interface, so that
|
||||
* the CMAC value can be computed incrementally over a message
|
||||
* scattered in different segments throughout memory. Experience shows
|
||||
* this style of interface tends to minimize the burden of programming
|
||||
* correctly. Like all symmetric key operations, it is session
|
||||
* oriented.
|
||||
*
|
||||
* To begin a CMAC session, use tc_cmac_setup to initialize a struct
|
||||
* tc_cmac_struct with encryption key and buffer. Our implementation
|
||||
* always assume that the AES key to be the same size as the block
|
||||
* cipher block size. Once setup, this data structure can be used for
|
||||
* many CMAC computations.
|
||||
*
|
||||
* Once the state has been setup with a key, computing the CMAC of
|
||||
* some data requires three steps:
|
||||
*
|
||||
* (1) first use tc_cmac_init to initialize a new CMAC computation.
|
||||
* (2) next mix all of the data into the CMAC computation state using
|
||||
* tc_cmac_update. If all of the data resides in a single data
|
||||
* segment then only one tc_cmac_update call is needed; if data
|
||||
* is scattered throughout memory in n data segments, then n calls
|
||||
* will be needed. CMAC IS ORDER SENSITIVE, to be able to detect
|
||||
* attacks that swap bytes, so the order in which data is mixed
|
||||
* into the state is critical!
|
||||
* (3) Once all of the data for a message has been mixed, use
|
||||
* tc_cmac_final to compute the CMAC tag value.
|
||||
*
|
||||
* Steps (1)-(3) can be repeated as many times as you want to CMAC
|
||||
* multiple messages. A practical limit is 2^48 1K messages before you
|
||||
* have to change the key.
|
||||
*
|
||||
* Once you are done computing CMAC with a key, it is a good idea to
|
||||
* destroy the state so an attacker cannot recover the key; use
|
||||
* tc_cmac_erase to accomplish this.
|
||||
*/
|
||||
|
||||
#ifndef __TC_CMAC_MODE_H__
|
||||
#define __TC_CMAC_MODE_H__
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* padding for last message block */
|
||||
#define TC_CMAC_PADDING 0x80
|
||||
|
||||
/* struct tc_cmac_struct represents the state of a CMAC computation */
|
||||
typedef struct tc_cmac_struct {
|
||||
/* initialization vector */
|
||||
uint8_t iv[TC_AES_BLOCK_SIZE];
|
||||
/* used if message length is a multiple of block_size bytes */
|
||||
uint8_t K1[TC_AES_BLOCK_SIZE];
|
||||
/* used if message length isn't a multiple block_size bytes */
|
||||
uint8_t K2[TC_AES_BLOCK_SIZE];
|
||||
/* where to put bytes that didn't fill a block */
|
||||
uint8_t leftover[TC_AES_BLOCK_SIZE];
|
||||
/* identifies the encryption key */
|
||||
unsigned int keyid;
|
||||
/* next available leftover location */
|
||||
unsigned int leftover_offset;
|
||||
/* AES key schedule */
|
||||
TCAesKeySched_t sched;
|
||||
/* calls to tc_cmac_update left before re-key */
|
||||
uint64_t countdown;
|
||||
} *TCCmacState_t;
|
||||
|
||||
/**
|
||||
* @brief Configures the CMAC state to use the given AES key
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL or
|
||||
* key == NULL
|
||||
*
|
||||
* @param s IN/OUT -- the state to set up
|
||||
* @param key IN -- the key to use
|
||||
* @param sched IN -- AES key schedule
|
||||
*/
|
||||
int tc_cmac_setup(TCCmacState_t s, const uint8_t *key,
|
||||
TCAesKeySched_t sched);
|
||||
|
||||
/**
|
||||
* @brief Erases the CMAC state
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL
|
||||
*
|
||||
* @param s IN/OUT -- the state to erase
|
||||
*/
|
||||
int tc_cmac_erase(TCCmacState_t s);
|
||||
|
||||
/**
|
||||
* @brief Initializes a new CMAC computation
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL
|
||||
*
|
||||
* @param s IN/OUT -- the state to initialize
|
||||
*/
|
||||
int tc_cmac_init(TCCmacState_t s);
|
||||
|
||||
/**
|
||||
* @brief Incrementally computes CMAC over the next data segment
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL or
|
||||
* if data == NULL when dlen > 0
|
||||
*
|
||||
* @param s IN/OUT -- the CMAC state
|
||||
* @param data IN -- the next data segment to MAC
|
||||
* @param dlen IN -- the length of data in bytes
|
||||
*/
|
||||
int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t dlen);
|
||||
|
||||
/**
|
||||
* @brief Generates the tag from the CMAC state
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* tag == NULL or
|
||||
* s == NULL
|
||||
*
|
||||
* @param tag OUT -- the CMAC tag
|
||||
* @param s IN -- CMAC state
|
||||
*/
|
||||
int tc_cmac_final(uint8_t *tag, TCCmacState_t s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CMAC_MODE_H__ */
|
||||
@@ -0,0 +1,61 @@
|
||||
/* constants.h - TinyCrypt interface to constants */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief -- Interface to constants.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TC_CONSTANTS_H__
|
||||
#define __TC_CONSTANTS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define TC_CRYPTO_SUCCESS 1
|
||||
#define TC_CRYPTO_FAIL 0
|
||||
|
||||
#define TC_ZERO_BYTE 0x00
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CONSTANTS_H__ */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* ctr_mode.h - TinyCrypt interface to CTR mode */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to CTR mode.
|
||||
*
|
||||
* Overview: CTR (pronounced "counter") mode is a NIST approved mode of
|
||||
* operation defined in SP 800-38a. It can be used with any
|
||||
* block cipher to provide confidentiality of strings of any
|
||||
* length. TinyCrypt hard codes AES128 as the block cipher.
|
||||
*
|
||||
* Security: CTR mode achieves confidentiality only if the counter value is
|
||||
* never reused with a same encryption key. If the counter is
|
||||
* repeated, than an adversary might be able to defeat the scheme.
|
||||
*
|
||||
* A usual method to ensure different counter values refers to
|
||||
* initialize the counter in a given value (0, for example) and
|
||||
* increases it every time a new block is enciphered. This naturally
|
||||
* leaves to a limitation on the number q of blocks that can be
|
||||
* enciphered using a same key: q < 2^(counter size).
|
||||
*
|
||||
* TinyCrypt uses a counter of 32 bits. This means that after 2^32
|
||||
* block encryptions, the counter will be reused (thus losing CBC
|
||||
* security). 2^32 block encryptions should be enough for most of
|
||||
* applications targeting constrained devices. Applications intended
|
||||
* to encrypt a larger number of blocks must replace the key after
|
||||
* 2^32 block encryptions.
|
||||
*
|
||||
* CTR mode provides NO data integrity.
|
||||
*
|
||||
* Requires: AES-128
|
||||
*
|
||||
* Usage: 1) call tc_ctr_mode to process the data to encrypt/decrypt.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TC_CTR_MODE_H__
|
||||
#define __TC_CTR_MODE_H__
|
||||
|
||||
#include "aes.h"
|
||||
#include "constants.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief CTR mode encryption/decryption procedure.
|
||||
* CTR mode encrypts (or decrypts) inlen bytes from in buffer into out buffer
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL or
|
||||
* in == NULL or
|
||||
* ctr == NULL or
|
||||
* sched == NULL or
|
||||
* inlen == 0 or
|
||||
* outlen == 0 or
|
||||
* inlen != outlen
|
||||
* @note Assumes:- The current value in ctr has NOT been used with sched
|
||||
* - out points to inlen bytes
|
||||
* - in points to inlen bytes
|
||||
* - ctr is an integer counter in littleEndian format
|
||||
* - sched was initialized by aes_set_encrypt_key
|
||||
* @param out OUT -- produced ciphertext (plaintext)
|
||||
* @param outlen IN -- length of ciphertext buffer in bytes
|
||||
* @param in IN -- data to encrypt (or decrypt)
|
||||
* @param inlen IN -- length of input data in bytes
|
||||
* @param ctr IN/OUT -- the current counter value
|
||||
* @param sched IN -- an initialized AES key schedule
|
||||
*/
|
||||
int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CTR_MODE_H__ */
|
||||
@@ -0,0 +1,166 @@
|
||||
/* ctr_prng.h - TinyCrypt interface to a CTR-PRNG implementation */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016, Chris Morrison
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to a CTR-PRNG implementation.
|
||||
*
|
||||
* Overview: A pseudo-random number generator (PRNG) generates a sequence
|
||||
* of numbers that have a distribution close to the one expected
|
||||
* for a sequence of truly random numbers. The NIST Special
|
||||
* Publication 800-90A specifies several mechanisms to generate
|
||||
* sequences of pseudo random numbers, including the CTR-PRNG one
|
||||
* which is based on AES. TinyCrypt implements CTR-PRNG with
|
||||
* AES-128.
|
||||
*
|
||||
* Security: A cryptographically secure PRNG depends on the existence of an
|
||||
* entropy source to provide a truly random seed as well as the
|
||||
* security of the primitives used as the building blocks (AES-128
|
||||
* in this instance).
|
||||
*
|
||||
* Requires: - AES-128
|
||||
*
|
||||
* Usage: 1) call tc_ctr_prng_init to seed the prng context
|
||||
*
|
||||
* 2) call tc_ctr_prng_reseed to mix in additional entropy into
|
||||
* the prng context
|
||||
*
|
||||
* 3) call tc_ctr_prng_generate to output the pseudo-random data
|
||||
*
|
||||
* 4) call tc_ctr_prng_uninstantiate to zero out the prng context
|
||||
*/
|
||||
|
||||
#ifndef __TC_CTR_PRNG_H__
|
||||
#define __TC_CTR_PRNG_H__
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#define TC_CTR_PRNG_RESEED_REQ -1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* updated each time another BLOCKLEN_BYTES bytes are produced */
|
||||
uint8_t V[TC_AES_BLOCK_SIZE];
|
||||
|
||||
/* updated whenever the PRNG is reseeded */
|
||||
struct tc_aes_key_sched_struct key;
|
||||
|
||||
/* number of requests since initialization/reseeding */
|
||||
uint64_t reseedCount;
|
||||
} TCCtrPrng_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief CTR-PRNG initialization procedure
|
||||
* Initializes prng context with entropy and personalization string (if any)
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* ctx == NULL,
|
||||
* entropy == NULL,
|
||||
* entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
|
||||
* @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of
|
||||
* both the entropy and personalization inputs are used -
|
||||
* supplying additional bytes has no effect.
|
||||
* @param ctx IN/OUT -- the PRNG context to initialize
|
||||
* @param entropy IN -- entropy used to seed the PRNG
|
||||
* @param entropyLen IN -- entropy length in bytes
|
||||
* @param personalization IN -- personalization string used to seed the PRNG
|
||||
* (may be null)
|
||||
* @param plen IN -- personalization length in bytes
|
||||
*
|
||||
*/
|
||||
int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const entropy,
|
||||
unsigned int entropyLen,
|
||||
uint8_t const * const personalization,
|
||||
unsigned int pLen);
|
||||
|
||||
/**
|
||||
* @brief CTR-PRNG reseed procedure
|
||||
* Mixes entropy and additional_input into the prng context
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* ctx == NULL,
|
||||
* entropy == NULL,
|
||||
* entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
|
||||
* @note It is better to reseed an existing prng context rather than
|
||||
* re-initialise, so that any existing entropy in the context is
|
||||
* presereved. This offers some protection against undetected failures
|
||||
* of the entropy source.
|
||||
* @note Assumes tc_ctr_prng_init has been called for ctx
|
||||
* @param ctx IN/OUT -- the PRNG state
|
||||
* @param entropy IN -- entropy to mix into the prng
|
||||
* @param entropylen IN -- length of entropy in bytes
|
||||
* @param additional_input IN -- additional input to the prng (may be null)
|
||||
* @param additionallen IN -- additional input length in bytes
|
||||
*/
|
||||
int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const entropy,
|
||||
unsigned int entropyLen,
|
||||
uint8_t const * const additional_input,
|
||||
unsigned int additionallen);
|
||||
|
||||
/**
|
||||
* @brief CTR-PRNG generate procedure
|
||||
* Generates outlen pseudo-random bytes into out buffer, updates prng
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CTR_PRNG_RESEED_REQ (-1) if a reseed is needed
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* ctx == NULL,
|
||||
* out == NULL,
|
||||
* outlen >= 2^16
|
||||
* @note Assumes tc_ctr_prng_init has been called for ctx
|
||||
* @param ctx IN/OUT -- the PRNG context
|
||||
* @param additional_input IN -- additional input to the prng (may be null)
|
||||
* @param additionallen IN -- additional input length in bytes
|
||||
* @param out IN/OUT -- buffer to receive output
|
||||
* @param outlen IN -- size of out buffer in bytes
|
||||
*/
|
||||
int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const additional_input,
|
||||
unsigned int additionallen,
|
||||
uint8_t * const out,
|
||||
unsigned int outlen);
|
||||
|
||||
/**
|
||||
* @brief CTR-PRNG uninstantiate procedure
|
||||
* Zeroes the internal state of the supplied prng context
|
||||
* @return none
|
||||
* @param ctx IN/OUT -- the PRNG context
|
||||
*/
|
||||
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_CTR_PRNG_H__ */
|
||||
@@ -0,0 +1,545 @@
|
||||
/* ecc.h - TinyCrypt interface to common ECC functions */
|
||||
|
||||
/* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief -- Interface to common ECC functions.
|
||||
*
|
||||
* Overview: This software is an implementation of common functions
|
||||
* necessary to elliptic curve cryptography. This implementation uses
|
||||
* curve NIST p-256.
|
||||
*
|
||||
* Security: The curve NIST p-256 provides approximately 128 bits of security.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TC_UECC_H__
|
||||
#define __TC_UECC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Word size (4 bytes considering 32-bits architectures) */
|
||||
#define uECC_WORD_SIZE 4
|
||||
|
||||
/* setting max number of calls to prng: */
|
||||
#ifndef uECC_RNG_MAX_TRIES
|
||||
#define uECC_RNG_MAX_TRIES 64
|
||||
#endif
|
||||
|
||||
/* defining data types to store word and bit counts: */
|
||||
typedef int8_t wordcount_t;
|
||||
typedef int16_t bitcount_t;
|
||||
/* defining data type for comparison result: */
|
||||
typedef int8_t cmpresult_t;
|
||||
/* defining data type to store ECC coordinate/point in 32bits words: */
|
||||
typedef unsigned int uECC_word_t;
|
||||
/* defining data type to store an ECC coordinate/point in 64bits words: */
|
||||
typedef uint64_t uECC_dword_t;
|
||||
|
||||
/* defining masks useful for ecc computations: */
|
||||
#define HIGH_BIT_SET 0x80000000
|
||||
#define uECC_WORD_BITS 32
|
||||
#define uECC_WORD_BITS_SHIFT 5
|
||||
#define uECC_WORD_BITS_MASK 0x01F
|
||||
|
||||
/* Number of words of 32 bits to represent an element of the the curve p-256: */
|
||||
#define NUM_ECC_WORDS 8
|
||||
/* Number of bytes to represent an element of the the curve p-256: */
|
||||
#define NUM_ECC_BYTES (uECC_WORD_SIZE*NUM_ECC_WORDS)
|
||||
|
||||
/* structure that represents an elliptic curve (e.g. p256):*/
|
||||
struct uECC_Curve_t;
|
||||
typedef const struct uECC_Curve_t * uECC_Curve;
|
||||
struct uECC_Curve_t {
|
||||
wordcount_t num_words;
|
||||
wordcount_t num_bytes;
|
||||
bitcount_t num_n_bits;
|
||||
uECC_word_t p[NUM_ECC_WORDS];
|
||||
uECC_word_t n[NUM_ECC_WORDS];
|
||||
uECC_word_t G[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t b[NUM_ECC_WORDS];
|
||||
void (*double_jacobian)(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1,
|
||||
uECC_Curve curve);
|
||||
void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
|
||||
void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief computes doubling of point ion jacobian coordinates, in place.
|
||||
* @param X1 IN/OUT -- x coordinate
|
||||
* @param Y1 IN/OUT -- y coordinate
|
||||
* @param Z1 IN/OUT -- z coordinate
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
|
||||
uECC_word_t * Z1, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Computes x^3 + ax + b. result must not overlap x.
|
||||
* @param result OUT -- x^3 + ax + b
|
||||
* @param x IN -- value of x
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void x_side_default(uECC_word_t *result, const uECC_word_t *x,
|
||||
uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Computes result = product % curve_p
|
||||
* from http://www.nsa.gov/ia/_files/nist-routines.pdf
|
||||
* @param result OUT -- product % curve_p
|
||||
* @param product IN -- value to be reduced mod curve_p
|
||||
*/
|
||||
void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int *product);
|
||||
|
||||
/* Bytes to words ordering: */
|
||||
#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e
|
||||
#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a
|
||||
#define BITS_TO_WORDS(num_bits) \
|
||||
((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8))
|
||||
#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8)
|
||||
|
||||
/* definition of curve NIST p-256: */
|
||||
static const struct uECC_Curve_t curve_secp256r1 = {
|
||||
NUM_ECC_WORDS,
|
||||
NUM_ECC_BYTES,
|
||||
256, /* num_n_bits */ {
|
||||
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
|
||||
BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
|
||||
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
|
||||
BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
|
||||
}, {
|
||||
BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
|
||||
BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
|
||||
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
|
||||
BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
|
||||
}, {
|
||||
BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
|
||||
BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
|
||||
BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
|
||||
BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
|
||||
|
||||
BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
|
||||
BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
|
||||
BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
|
||||
BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
|
||||
}, {
|
||||
BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
|
||||
BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
|
||||
BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
|
||||
BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
|
||||
},
|
||||
&double_jacobian_default,
|
||||
&x_side_default,
|
||||
&vli_mmod_fast_secp256r1
|
||||
};
|
||||
|
||||
uECC_Curve uECC_secp256r1(void);
|
||||
|
||||
/*
|
||||
* @brief Generates a random integer in the range 0 < random < top.
|
||||
* Both random and top have num_words words.
|
||||
* @param random OUT -- random integer in the range 0 < random < top
|
||||
* @param top IN -- upper limit
|
||||
* @param num_words IN -- number of words
|
||||
* @return a random integer in the range 0 < random < top
|
||||
*/
|
||||
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
|
||||
wordcount_t num_words);
|
||||
|
||||
|
||||
/* uECC_RNG_Function type
|
||||
* The RNG function should fill 'size' random bytes into 'dest'. It should
|
||||
* return 1 if 'dest' was filled with random data, or 0 if the random data could
|
||||
* not be generated. The filled-in values should be either truly random, or from
|
||||
* a cryptographically-secure PRNG.
|
||||
*
|
||||
* A correctly functioning RNG function must be set (using uECC_set_rng())
|
||||
* before calling uECC_make_key() or uECC_sign().
|
||||
*
|
||||
* Setting a correctly functioning RNG function improves the resistance to
|
||||
* side-channel attacks for uECC_shared_secret().
|
||||
*
|
||||
* A correct RNG function is set by default. If you are building on another
|
||||
* POSIX-compliant system that supports /dev/random or /dev/urandom, you can
|
||||
* define uECC_POSIX to use the predefined RNG.
|
||||
*/
|
||||
typedef int(*uECC_RNG_Function)(uint8_t *dest, unsigned int size);
|
||||
|
||||
/*
|
||||
* @brief Set the function that will be used to generate random bytes. The RNG
|
||||
* function should return 1 if the random data was generated, or 0 if the random
|
||||
* data could not be generated.
|
||||
*
|
||||
* @note On platforms where there is no predefined RNG function, this must be
|
||||
* called before uECC_make_key() or uECC_sign() are used.
|
||||
*
|
||||
* @param rng_function IN -- function that will be used to generate random bytes
|
||||
*/
|
||||
void uECC_set_rng(uECC_RNG_Function rng_function);
|
||||
|
||||
/*
|
||||
* @brief provides current uECC_RNG_Function.
|
||||
* @return Returns the function that will be used to generate random bytes.
|
||||
*/
|
||||
uECC_RNG_Function uECC_get_rng(void);
|
||||
|
||||
/*
|
||||
* @brief computes the size of a private key for the curve in bytes.
|
||||
* @param curve IN -- elliptic curve
|
||||
* @return size of a private key for the curve in bytes.
|
||||
*/
|
||||
int uECC_curve_private_key_size(uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief computes the size of a public key for the curve in bytes.
|
||||
* @param curve IN -- elliptic curve
|
||||
* @return the size of a public key for the curve in bytes.
|
||||
*/
|
||||
int uECC_curve_public_key_size(uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Compute the corresponding public key for a private key.
|
||||
* @param private_key IN -- The private key to compute the public key for
|
||||
* @param public_key OUT -- Will be filled in with the corresponding public key
|
||||
* @param curve
|
||||
* @return Returns 1 if key was computed successfully, 0 if an error occurred.
|
||||
*/
|
||||
int uECC_compute_public_key(const uint8_t *private_key,
|
||||
uint8_t *public_key, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Compute public-key.
|
||||
* @return corresponding public-key.
|
||||
* @param result OUT -- public-key
|
||||
* @param private_key IN -- private-key
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
|
||||
uECC_word_t *private_key, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Regularize the bitcount for the private key so that attackers cannot
|
||||
* use a side channel attack to learn the number of leading zeros.
|
||||
* @return Regularized k
|
||||
* @param k IN -- private-key
|
||||
* @param k0 IN/OUT -- regularized k
|
||||
* @param k1 IN/OUT -- regularized k
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
|
||||
uECC_word_t *k1, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Point multiplication algorithm using Montgomery's ladder with co-Z
|
||||
* coordinates. See http://eprint.iacr.org/2011/338.pdf.
|
||||
* @note Result may overlap point.
|
||||
* @param result OUT -- returns scalar*point
|
||||
* @param point IN -- elliptic curve point
|
||||
* @param scalar IN -- scalar
|
||||
* @param initial_Z IN -- initial value for z
|
||||
* @param num_bits IN -- number of bits in scalar
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
|
||||
const uECC_word_t * scalar, const uECC_word_t * initial_Z,
|
||||
bitcount_t num_bits, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Constant-time comparison to zero - secure way to compare long integers
|
||||
* @param vli IN -- very long integer
|
||||
* @param num_words IN -- number of words in the vli
|
||||
* @return 1 if vli == 0, 0 otherwise.
|
||||
*/
|
||||
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Check if 'point' is the point at infinity
|
||||
* @param point IN -- elliptic curve point
|
||||
* @param curve IN -- elliptic curve
|
||||
* @return if 'point' is the point at infinity, 0 otherwise.
|
||||
*/
|
||||
uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief computes the sign of left - right, in constant time.
|
||||
* @param left IN -- left term to be compared
|
||||
* @param right IN -- right term to be compared
|
||||
* @param num_words IN -- number of words
|
||||
* @return the sign of left - right
|
||||
*/
|
||||
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief computes sign of left - right, not in constant time.
|
||||
* @note should not be used if inputs are part of a secret
|
||||
* @param left IN -- left term to be compared
|
||||
* @param right IN -- right term to be compared
|
||||
* @param num_words IN -- number of words
|
||||
* @return the sign of left - right
|
||||
*/
|
||||
cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes result = (left - right) % mod.
|
||||
* @note Assumes that (left < mod) and (right < mod), and that result does not
|
||||
* overlap mod.
|
||||
* @param result OUT -- (left - right) % mod
|
||||
* @param left IN -- leftright term in modular subtraction
|
||||
* @param right IN -- right term in modular subtraction
|
||||
* @param mod IN -- mod
|
||||
* @param num_words IN -- number of words
|
||||
*/
|
||||
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or
|
||||
* P => P', Q => P + Q
|
||||
* @note assumes Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
* @param X1 IN -- x coordinate of P
|
||||
* @param Y1 IN -- y coordinate of P
|
||||
* @param X2 IN -- x coordinate of Q
|
||||
* @param Y2 IN -- y coordinate of Q
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2,
|
||||
uECC_word_t * Y2, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Computes (x1 * z^2, y1 * z^3)
|
||||
* @param X1 IN -- previous x1 coordinate
|
||||
* @param Y1 IN -- previous y1 coordinate
|
||||
* @param Z IN -- z value
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z,
|
||||
uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Check if bit is set.
|
||||
* @return Returns nonzero if bit 'bit' of vli is set.
|
||||
* @warning It is assumed that the value provided in 'bit' is within the
|
||||
* boundaries of the word-array 'vli'.
|
||||
* @note The bit ordering layout assumed for vli is: {31, 30, ..., 0},
|
||||
* {63, 62, ..., 32}, {95, 94, ..., 64}, {127, 126,..., 96} for a vli consisting
|
||||
* of 4 uECC_word_t elements.
|
||||
*/
|
||||
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
|
||||
|
||||
/*
|
||||
* @brief Computes result = product % mod, where product is 2N words long.
|
||||
* @param result OUT -- product % mod
|
||||
* @param mod IN -- module
|
||||
* @param num_words IN -- number of words
|
||||
* @warning Currently only designed to work for curve_p or curve_n.
|
||||
*/
|
||||
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
|
||||
const uECC_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes modular product (using curve->mmod_fast)
|
||||
* @param result OUT -- (left * right) mod % curve_p
|
||||
* @param left IN -- left term in product
|
||||
* @param right IN -- right term in product
|
||||
* @param curve IN -- elliptic curve
|
||||
*/
|
||||
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Computes result = left - right.
|
||||
* @note Can modify in place.
|
||||
* @param result OUT -- left - right
|
||||
* @param left IN -- left term in subtraction
|
||||
* @param right IN -- right term in subtraction
|
||||
* @param num_words IN -- number of words
|
||||
* @return borrow
|
||||
*/
|
||||
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Constant-time comparison function(secure way to compare long ints)
|
||||
* @param left IN -- left term in comparison
|
||||
* @param right IN -- right term in comparison
|
||||
* @param num_words IN -- number of words
|
||||
* @return Returns 0 if left == right, 1 otherwise.
|
||||
*/
|
||||
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes (left * right) % mod
|
||||
* @param result OUT -- (left * right) % mod
|
||||
* @param left IN -- left term in product
|
||||
* @param right IN -- right term in product
|
||||
* @param mod IN -- mod
|
||||
* @param num_words IN -- number of words
|
||||
*/
|
||||
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes (1 / input) % mod
|
||||
* @note All VLIs are the same size.
|
||||
* @note See "Euclid's GCD to Montgomery Multiplication to the Great Divide"
|
||||
* @param result OUT -- (1 / input) % mod
|
||||
* @param input IN -- value to be modular inverted
|
||||
* @param mod IN -- mod
|
||||
* @param num_words -- number of words
|
||||
*/
|
||||
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
|
||||
const uECC_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Sets dest = src.
|
||||
* @param dest OUT -- destination buffer
|
||||
* @param src IN -- origin buffer
|
||||
* @param num_words IN -- number of words
|
||||
*/
|
||||
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Computes (left + right) % mod.
|
||||
* @note Assumes that (left < mod) and right < mod), and that result does not
|
||||
* overlap mod.
|
||||
* @param result OUT -- (left + right) % mod.
|
||||
* @param left IN -- left term in addition
|
||||
* @param right IN -- right term in addition
|
||||
* @param mod IN -- mod
|
||||
* @param num_words IN -- number of words
|
||||
*/
|
||||
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief Counts the number of bits required to represent vli.
|
||||
* @param vli IN -- very long integer
|
||||
* @param max_words IN -- number of words
|
||||
* @return number of bits in given vli
|
||||
*/
|
||||
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
|
||||
const wordcount_t max_words);
|
||||
|
||||
/*
|
||||
* @brief Erases (set to 0) vli
|
||||
* @param vli IN -- very long integer
|
||||
* @param num_words IN -- number of words
|
||||
*/
|
||||
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/*
|
||||
* @brief check if it is a valid point in the curve
|
||||
* @param point IN -- point to be checked
|
||||
* @param curve IN -- elliptic curve
|
||||
* @return 0 if point is valid
|
||||
* @exception returns -1 if it is a point at infinity
|
||||
* @exception returns -2 if x or y is smaller than p,
|
||||
* @exception returns -3 if y^2 != x^3 + ax + b.
|
||||
*/
|
||||
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Check if a public key is valid.
|
||||
* @param public_key IN -- The public key to be checked.
|
||||
* @return returns 0 if the public key is valid
|
||||
* @exception returns -1 if it is a point at infinity
|
||||
* @exception returns -2 if x or y is smaller than p,
|
||||
* @exception returns -3 if y^2 != x^3 + ax + b.
|
||||
* @exception returns -4 if public key is the group generator.
|
||||
*
|
||||
* @note Note that you are not required to check for a valid public key before
|
||||
* using any other uECC functions. However, you may wish to avoid spending CPU
|
||||
* time computing a shared secret or verifying a signature using an invalid
|
||||
* public key.
|
||||
*/
|
||||
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
|
||||
|
||||
/*
|
||||
* @brief Converts an integer in uECC native format to big-endian bytes.
|
||||
* @param bytes OUT -- bytes representation
|
||||
* @param num_bytes IN -- number of bytes
|
||||
* @param native IN -- uECC native representation
|
||||
*/
|
||||
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
|
||||
const unsigned int *native);
|
||||
|
||||
/*
|
||||
* @brief Converts big-endian bytes to an integer in uECC native format.
|
||||
* @param native OUT -- uECC native representation
|
||||
* @param bytes IN -- bytes representation
|
||||
* @param num_bytes IN -- number of bytes
|
||||
*/
|
||||
void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
|
||||
int num_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_UECC_H__ */
|
||||
@@ -0,0 +1,131 @@
|
||||
/* ecc_dh.h - TinyCrypt interface to EC-DH implementation */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief -- Interface to EC-DH implementation.
|
||||
*
|
||||
* Overview: This software is an implementation of EC-DH. This implementation
|
||||
* uses curve NIST p-256.
|
||||
*
|
||||
* Security: The curve NIST p-256 provides approximately 128 bits of security.
|
||||
*/
|
||||
|
||||
#ifndef __TC_ECC_DH_H__
|
||||
#define __TC_ECC_DH_H__
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a public/private key pair.
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) if the key pair was generated successfully
|
||||
* returns TC_CRYPTO_FAIL (0) if error while generating key pair
|
||||
*
|
||||
* @param p_public_key OUT -- Will be filled in with the public key. Must be at
|
||||
* least 2 * the curve size (in bytes) long. For curve secp256r1, p_public_key
|
||||
* must be 64 bytes long.
|
||||
* @param p_private_key OUT -- Will be filled in with the private key. Must be as
|
||||
* long as the curve order (for secp256r1, p_private_key must be 32 bytes long).
|
||||
*
|
||||
* @note side-channel countermeasure: algorithm strengthened against timing
|
||||
* attack.
|
||||
* @warning A cryptographically-secure PRNG function must be set (using
|
||||
* uECC_set_rng()) before calling uECC_make_key().
|
||||
*/
|
||||
int uECC_make_key(uint8_t *p_public_key, uint8_t *p_private_key, uECC_Curve curve);
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
|
||||
/**
|
||||
* @brief Create a public/private key pair given a specific d.
|
||||
*
|
||||
* @note THIS FUNCTION SHOULD BE CALLED ONLY FOR TEST PURPOSES. Refer to
|
||||
* uECC_make_key() function for real applications.
|
||||
*/
|
||||
int uECC_make_key_with_d(uint8_t *p_public_key, uint8_t *p_private_key,
|
||||
unsigned int *d, uECC_Curve curve);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Compute a shared secret given your secret key and someone else's
|
||||
* public key.
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) if the shared secret was computed successfully
|
||||
* returns TC_CRYPTO_FAIL (0) otherwise
|
||||
*
|
||||
* @param p_secret OUT -- Will be filled in with the shared secret value. Must be
|
||||
* the same size as the curve size (for curve secp256r1, secret must be 32 bytes
|
||||
* long.
|
||||
* @param p_public_key IN -- The public key of the remote party.
|
||||
* @param p_private_key IN -- Your private key.
|
||||
*
|
||||
* @warning It is recommended to use the output of uECC_shared_secret() as the
|
||||
* input of a recommended Key Derivation Function (see NIST SP 800-108) in
|
||||
* order to produce a cryptographically secure symmetric key.
|
||||
*/
|
||||
int uECC_shared_secret(const uint8_t *p_public_key, const uint8_t *p_private_key,
|
||||
uint8_t *p_secret, uECC_Curve curve);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_ECC_DH_H__ */
|
||||
@@ -0,0 +1,139 @@
|
||||
/* ecc_dh.h - TinyCrypt interface to EC-DSA implementation */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief -- Interface to EC-DSA implementation.
|
||||
*
|
||||
* Overview: This software is an implementation of EC-DSA. This implementation
|
||||
* uses curve NIST p-256.
|
||||
*
|
||||
* Security: The curve NIST p-256 provides approximately 128 bits of security.
|
||||
*
|
||||
* Usage: - To sign: Compute a hash of the data you wish to sign (SHA-2 is
|
||||
* recommended) and pass it in to ecdsa_sign function along with your
|
||||
* private key and a random number. You must use a new non-predictable
|
||||
* random number to generate each new signature.
|
||||
* - To verify a signature: Compute the hash of the signed data using
|
||||
* the same hash as the signer and pass it to this function along with
|
||||
* the signer's public key and the signature values (r and s).
|
||||
*/
|
||||
|
||||
#ifndef __TC_ECC_DSA_H__
|
||||
#define __TC_ECC_DSA_H__
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generate an ECDSA signature for a given hash value.
|
||||
* @return returns TC_CRYPTO_SUCCESS (1) if the signature generated successfully
|
||||
* returns TC_CRYPTO_FAIL (0) if an error occurred.
|
||||
*
|
||||
* @param p_private_key IN -- Your private key.
|
||||
* @param p_message_hash IN -- The hash of the message to sign.
|
||||
* @param p_hash_size IN -- The size of p_message_hash in bytes.
|
||||
* @param p_signature OUT -- Will be filled in with the signature value. Must be
|
||||
* at least 2 * curve size long (for secp256r1, signature must be 64 bytes long).
|
||||
*
|
||||
* @warning A cryptographically-secure PRNG function must be set (using
|
||||
* uECC_set_rng()) before calling uECC_sign().
|
||||
* @note Usage: Compute a hash of the data you wish to sign (SHA-2 is
|
||||
* recommended) and pass it in to this function along with your private key.
|
||||
* @note side-channel countermeasure: algorithm strengthened against timing
|
||||
* attack.
|
||||
*/
|
||||
int uECC_sign(const uint8_t *p_private_key, const uint8_t *p_message_hash,
|
||||
unsigned p_hash_size, uint8_t *p_signature, uECC_Curve curve);
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
/*
|
||||
* THIS FUNCTION SHOULD BE CALLED FOR TEST PURPOSES ONLY.
|
||||
* Refer to uECC_sign() function for real applications.
|
||||
*/
|
||||
int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned int hash_size, uECC_word_t *k, uint8_t *signature,
|
||||
uECC_Curve curve);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Verify an ECDSA signature.
|
||||
* @return returns TC_SUCCESS (1) if the signature is valid
|
||||
* returns TC_FAIL (0) if the signature is invalid.
|
||||
*
|
||||
* @param p_public_key IN -- The signer's public key.
|
||||
* @param p_message_hash IN -- The hash of the signed data.
|
||||
* @param p_hash_size IN -- The size of p_message_hash in bytes.
|
||||
* @param p_signature IN -- The signature values.
|
||||
*
|
||||
* @note Usage: Compute the hash of the signed data using the same hash as the
|
||||
* signer and pass it to this function along with the signer's public key and
|
||||
* the signature values (hash_size and signature).
|
||||
*/
|
||||
int uECC_verify(const uint8_t *p_public_key, const uint8_t *p_message_hash,
|
||||
unsigned int p_hash_size, const uint8_t *p_signature, uECC_Curve curve);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_ECC_DSA_H__ */
|
||||
@@ -0,0 +1,81 @@
|
||||
/* uECC_platform_specific.h - Interface to platform specific functions*/
|
||||
|
||||
/* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*
|
||||
* uECC_platform_specific.h -- Interface to platform specific functions
|
||||
*/
|
||||
|
||||
#ifndef __UECC_PLATFORM_SPECIFIC_H_
|
||||
#define __UECC_PLATFORM_SPECIFIC_H_
|
||||
|
||||
/*
|
||||
* The RNG function should fill 'size' random bytes into 'dest'. It should
|
||||
* return 1 if 'dest' was filled with random data, or 0 if the random data could
|
||||
* not be generated. The filled-in values should be either truly random, or from
|
||||
* a cryptographically-secure PRNG.
|
||||
*
|
||||
* A cryptographically-secure PRNG function must be set (using uECC_set_rng())
|
||||
* before calling uECC_make_key() or uECC_sign().
|
||||
*
|
||||
* Setting a cryptographically-secure PRNG function improves the resistance to
|
||||
* side-channel attacks for uECC_shared_secret().
|
||||
*
|
||||
* A correct PRNG function is set by default (default_RNG_defined = 1) and works
|
||||
* for some platforms, such as Unix and Linux. For other platforms, you may need
|
||||
* to provide another PRNG function.
|
||||
*/
|
||||
#define default_RNG_defined 0
|
||||
|
||||
int default_CSPRNG(uint8_t *dest, unsigned int size);
|
||||
|
||||
#endif /* __UECC_PLATFORM_SPECIFIC_H_ */
|
||||
@@ -0,0 +1,139 @@
|
||||
/* hmac.h - TinyCrypt interface to an HMAC implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to an HMAC implementation.
|
||||
*
|
||||
* Overview: HMAC is a message authentication code based on hash functions.
|
||||
* TinyCrypt hard codes SHA-256 as the hash function. A message
|
||||
* authentication code based on hash functions is also called a
|
||||
* keyed cryptographic hash function since it performs a
|
||||
* transformation specified by a key in an arbitrary length data
|
||||
* set into a fixed length data set (also called tag).
|
||||
*
|
||||
* Security: The security of the HMAC depends on the length of the key and
|
||||
* on the security of the hash function. Note that HMAC primitives
|
||||
* are much less affected by collision attacks than their
|
||||
* corresponding hash functions.
|
||||
*
|
||||
* Requires: SHA-256
|
||||
*
|
||||
* Usage: 1) call tc_hmac_set_key to set the HMAC key.
|
||||
*
|
||||
* 2) call tc_hmac_init to initialize a struct hash_state before
|
||||
* processing the data.
|
||||
*
|
||||
* 3) call tc_hmac_update to process the next input segment;
|
||||
* tc_hmac_update can be called as many times as needed to process
|
||||
* all of the segments of the input; the order is important.
|
||||
*
|
||||
* 4) call tc_hmac_final to out put the tag.
|
||||
*/
|
||||
|
||||
#ifndef __TC_HMAC_H__
|
||||
#define __TC_HMAC_H__
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct tc_hmac_state_struct {
|
||||
/* the internal state required by h */
|
||||
struct tc_sha256_state_struct hash_state;
|
||||
/* HMAC key schedule */
|
||||
uint8_t key[2*TC_SHA256_BLOCK_SIZE];
|
||||
};
|
||||
typedef struct tc_hmac_state_struct *TCHmacState_t;
|
||||
|
||||
/**
|
||||
* @brief HMAC set key procedure
|
||||
* Configures ctx to use key
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if
|
||||
* ctx == NULL or
|
||||
* key == NULL or
|
||||
* key_size == 0
|
||||
* @param ctx IN/OUT -- the struct tc_hmac_state_struct to initial
|
||||
* @param key IN -- the HMAC key to configure
|
||||
* @param key_size IN -- the HMAC key size
|
||||
*/
|
||||
int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key,
|
||||
unsigned int key_size);
|
||||
|
||||
/**
|
||||
* @brief HMAC initialize procedure
|
||||
* Initializes ctx to begin the next HMAC operation
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL
|
||||
* @param ctx IN/OUT -- struct tc_hmac_state_struct buffer to initialize
|
||||
*/
|
||||
int tc_hmac_init(TCHmacState_t ctx);
|
||||
|
||||
/**
|
||||
* @brief HMAC update procedure
|
||||
* Mixes data_length bytes addressed by data into state
|
||||
* @return returns TC_CRYPTO_SUCCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL
|
||||
* @note Assumes state has been initialized by tc_hmac_init
|
||||
* @param ctx IN/OUT -- state of HMAC computation so far
|
||||
* @param data IN -- data to incorporate into state
|
||||
* @param data_length IN -- size of data in bytes
|
||||
*/
|
||||
int tc_hmac_update(TCHmacState_t ctx, const void *data,
|
||||
unsigned int data_length);
|
||||
|
||||
/**
|
||||
* @brief HMAC final procedure
|
||||
* Writes the HMAC tag into the tag buffer
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* tag == NULL or
|
||||
* ctx == NULL or
|
||||
* key == NULL or
|
||||
* taglen != TC_SHA256_DIGEST_SIZE
|
||||
* @note ctx is erased before exiting. This should never be changed/removed.
|
||||
* @note Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes
|
||||
* state has been initialized by tc_hmac_init
|
||||
* @param tag IN/OUT -- buffer to receive computed HMAC tag
|
||||
* @param taglen IN -- size of tag in bytes
|
||||
* @param ctx IN/OUT -- the HMAC state for computing tag
|
||||
*/
|
||||
int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__TC_HMAC_H__*/
|
||||
@@ -0,0 +1,164 @@
|
||||
/* hmac_prng.h - TinyCrypt interface to an HMAC-PRNG implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to an HMAC-PRNG implementation.
|
||||
*
|
||||
* Overview: A pseudo-random number generator (PRNG) generates a sequence
|
||||
* of numbers that have a distribution close to the one expected
|
||||
* for a sequence of truly random numbers. The NIST Special
|
||||
* Publication 800-90A specifies several mechanisms to generate
|
||||
* sequences of pseudo random numbers, including the HMAC-PRNG one
|
||||
* which is based on HMAC. TinyCrypt implements HMAC-PRNG with
|
||||
* certain modifications from the NIST SP 800-90A spec.
|
||||
*
|
||||
* Security: A cryptographically secure PRNG depends on the existence of an
|
||||
* entropy source to provide a truly random seed as well as the
|
||||
* security of the primitives used as the building blocks (HMAC and
|
||||
* SHA256, for TinyCrypt).
|
||||
*
|
||||
* The NIST SP 800-90A standard tolerates a null personalization,
|
||||
* while TinyCrypt requires a non-null personalization. This is
|
||||
* because a personalization string (the host name concatenated
|
||||
* with a time stamp, for example) is easily computed and might be
|
||||
* the last line of defense against failure of the entropy source.
|
||||
*
|
||||
* Requires: - SHA-256
|
||||
* - HMAC
|
||||
*
|
||||
* Usage: 1) call tc_hmac_prng_init to set the HMAC key and process the
|
||||
* personalization data.
|
||||
*
|
||||
* 2) call tc_hmac_prng_reseed to process the seed and additional
|
||||
* input.
|
||||
*
|
||||
* 3) call tc_hmac_prng_generate to out put the pseudo-random data.
|
||||
*/
|
||||
|
||||
#ifndef __TC_HMAC_PRNG_H__
|
||||
#define __TC_HMAC_PRNG_H__
|
||||
|
||||
#include "sha256.h"
|
||||
#include "hmac.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TC_HMAC_PRNG_RESEED_REQ -1
|
||||
|
||||
struct tc_hmac_prng_struct {
|
||||
/* the HMAC instance for this PRNG */
|
||||
struct tc_hmac_state_struct h;
|
||||
/* the PRNG key */
|
||||
uint8_t key[TC_SHA256_DIGEST_SIZE];
|
||||
/* PRNG state */
|
||||
uint8_t v[TC_SHA256_DIGEST_SIZE];
|
||||
/* calls to tc_hmac_prng_generate left before re-seed */
|
||||
unsigned int countdown;
|
||||
};
|
||||
|
||||
typedef struct tc_hmac_prng_struct *TCHmacPrng_t;
|
||||
|
||||
/**
|
||||
* @brief HMAC-PRNG initialization procedure
|
||||
* Initializes prng with personalization, disables tc_hmac_prng_generate
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* prng == NULL,
|
||||
* personalization == NULL,
|
||||
* plen > MAX_PLEN
|
||||
* @note Assumes: - personalization != NULL.
|
||||
* The personalization is a platform unique string (e.g., the host
|
||||
* name) and is the last line of defense against failure of the
|
||||
* entropy source
|
||||
* @warning NIST SP 800-90A specifies 3 items as seed material during
|
||||
* initialization: entropy seed, personalization, and an optional
|
||||
* nonce. TinyCrypts requires instead a non-null personalization
|
||||
* (which is easily computed) and indirectly requires an entropy
|
||||
* seed (since the reseed function is mandatorily called after
|
||||
* initialize)
|
||||
* @param prng IN/OUT -- the PRNG state to initialize
|
||||
* @param personalization IN -- personalization string
|
||||
* @param plen IN -- personalization length in bytes
|
||||
*/
|
||||
int tc_hmac_prng_init(TCHmacPrng_t prng,
|
||||
const uint8_t *personalization,
|
||||
unsigned int plen);
|
||||
|
||||
/**
|
||||
* @brief HMAC-PRNG reseed procedure
|
||||
* Mixes seed into prng, enables tc_hmac_prng_generate
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* prng == NULL,
|
||||
* seed == NULL,
|
||||
* seedlen < MIN_SLEN,
|
||||
* seendlen > MAX_SLEN,
|
||||
* additional_input != (const uint8_t *) 0 && additionallen == 0,
|
||||
* additional_input != (const uint8_t *) 0 && additionallen > MAX_ALEN
|
||||
* @note Assumes:- tc_hmac_prng_init has been called for prng
|
||||
* - seed has sufficient entropy.
|
||||
*
|
||||
* @param prng IN/OUT -- the PRNG state
|
||||
* @param seed IN -- entropy to mix into the prng
|
||||
* @param seedlen IN -- length of seed in bytes
|
||||
* @param additional_input IN -- additional input to the prng
|
||||
* @param additionallen IN -- additional input length in bytes
|
||||
*/
|
||||
int tc_hmac_prng_reseed(TCHmacPrng_t prng, const uint8_t *seed,
|
||||
unsigned int seedlen, const uint8_t *additional_input,
|
||||
unsigned int additionallen);
|
||||
|
||||
/**
|
||||
* @brief HMAC-PRNG generate procedure
|
||||
* Generates outlen pseudo-random bytes into out buffer, updates prng
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_HMAC_PRNG_RESEED_REQ (-1) if a reseed is needed
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* out == NULL,
|
||||
* prng == NULL,
|
||||
* outlen == 0,
|
||||
* outlen >= MAX_OUT
|
||||
* @note Assumes tc_hmac_prng_init has been called for prng
|
||||
* @param out IN/OUT -- buffer to receive output
|
||||
* @param outlen IN -- size of out buffer in bytes
|
||||
* @param prng IN/OUT -- the PRNG state
|
||||
*/
|
||||
int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_HMAC_PRNG_H__ */
|
||||
@@ -0,0 +1,129 @@
|
||||
/* sha256.h - TinyCrypt interface to a SHA-256 implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to a SHA-256 implementation.
|
||||
*
|
||||
* Overview: SHA-256 is a NIST approved cryptographic hashing algorithm
|
||||
* specified in FIPS 180. A hash algorithm maps data of arbitrary
|
||||
* size to data of fixed length.
|
||||
*
|
||||
* Security: SHA-256 provides 128 bits of security against collision attacks
|
||||
* and 256 bits of security against pre-image attacks. SHA-256 does
|
||||
* NOT behave like a random oracle, but it can be used as one if
|
||||
* the string being hashed is prefix-free encoded before hashing.
|
||||
*
|
||||
* Usage: 1) call tc_sha256_init to initialize a struct
|
||||
* tc_sha256_state_struct before hashing a new string.
|
||||
*
|
||||
* 2) call tc_sha256_update to hash the next string segment;
|
||||
* tc_sha256_update can be called as many times as needed to hash
|
||||
* all of the segments of a string; the order is important.
|
||||
*
|
||||
* 3) call tc_sha256_final to out put the digest from a hashing
|
||||
* operation.
|
||||
*/
|
||||
|
||||
#ifndef __TC_SHA256_H__
|
||||
#define __TC_SHA256_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TC_SHA256_BLOCK_SIZE (64)
|
||||
#define TC_SHA256_DIGEST_SIZE (32)
|
||||
#define TC_SHA256_STATE_BLOCKS (TC_SHA256_DIGEST_SIZE/4)
|
||||
|
||||
struct tc_sha256_state_struct {
|
||||
unsigned int iv[TC_SHA256_STATE_BLOCKS];
|
||||
uint64_t bits_hashed;
|
||||
uint8_t leftover[TC_SHA256_BLOCK_SIZE];
|
||||
size_t leftover_offset;
|
||||
};
|
||||
|
||||
typedef struct tc_sha256_state_struct *TCSha256State_t;
|
||||
|
||||
/**
|
||||
* @brief SHA256 initialization procedure
|
||||
* Initializes s
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if s == NULL
|
||||
* @param s Sha256 state struct
|
||||
*/
|
||||
int tc_sha256_init(TCSha256State_t s);
|
||||
|
||||
/**
|
||||
* @brief SHA256 update procedure
|
||||
* Hashes data_length bytes addressed by data into state s
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL,
|
||||
* s->iv == NULL,
|
||||
* data == NULL
|
||||
* @note Assumes s has been initialized by tc_sha256_init
|
||||
* @warning The state buffer 'leftover' is left in memory after processing
|
||||
* If your application intends to have sensitive data in this
|
||||
* buffer, remind to erase it after the data has been processed
|
||||
* @param s Sha256 state struct
|
||||
* @param data message to hash
|
||||
* @param datalen length of message to hash
|
||||
*/
|
||||
int tc_sha256_update (TCSha256State_t s, const uint8_t *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* @brief SHA256 final procedure
|
||||
* Inserts the completed hash computation into digest
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* s == NULL,
|
||||
* s->iv == NULL,
|
||||
* digest == NULL
|
||||
* @note Assumes: s has been initialized by tc_sha256_init
|
||||
* digest points to at least TC_SHA256_DIGEST_SIZE bytes
|
||||
* @warning The state buffer 'leftover' is left in memory after processing
|
||||
* If your application intends to have sensitive data in this
|
||||
* buffer, remind to erase it after the data has been processed
|
||||
* @param digest unsigned eight bit integer
|
||||
* @param Sha256 state struct
|
||||
*/
|
||||
int tc_sha256_final(uint8_t *digest, TCSha256State_t s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_SHA256_H__ */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* utils.h - TinyCrypt interface to platform-dependent run-time operations */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Interface to platform-dependent run-time operations.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TC_UTILS_H__
|
||||
#define __TC_UTILS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Copy the the buffer 'from' to the buffer 'to'.
|
||||
* @return returns TC_CRYPTO_SUCCESS (1)
|
||||
* returns TC_CRYPTO_FAIL (0) if:
|
||||
* from_len > to_len.
|
||||
*
|
||||
* @param to OUT -- destination buffer
|
||||
* @param to_len IN -- length of destination buffer
|
||||
* @param from IN -- origin buffer
|
||||
* @param from_len IN -- length of origin buffer
|
||||
*/
|
||||
unsigned int _copy(uint8_t *to, unsigned int to_len,
|
||||
const uint8_t *from, unsigned int from_len);
|
||||
|
||||
/**
|
||||
* @brief Set the value 'val' into the buffer 'to', 'len' times.
|
||||
*
|
||||
* @param to OUT -- destination buffer
|
||||
* @param val IN -- value to be set in 'to'
|
||||
* @param len IN -- number of times the value will be copied
|
||||
*/
|
||||
void _set(void *to, uint8_t val, unsigned int len);
|
||||
|
||||
/*
|
||||
* @brief AES specific doubling function, which utilizes
|
||||
* the finite field used by AES.
|
||||
* @return Returns a^2
|
||||
*
|
||||
* @param a IN/OUT -- value to be doubled
|
||||
*/
|
||||
uint8_t _double_byte(uint8_t a);
|
||||
|
||||
/*
|
||||
* @brief Constant-time algorithm to compare if two sequences of bytes are equal
|
||||
* @return Returns 0 if equal, and non-zero otherwise
|
||||
*
|
||||
* @param a IN -- sequence of bytes a
|
||||
* @param b IN -- sequence of bytes b
|
||||
* @param size IN -- size of sequences a and b
|
||||
*/
|
||||
int _compare(const uint8_t *a, const uint8_t *b, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TC_UTILS_H__ */
|
||||
164
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_decrypt.c
Normal file
164
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_decrypt.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/* aes_decrypt.c - TinyCrypt implementation of AES decryption procedure */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/aes.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
static const uint8_t inv_sbox[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
|
||||
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
||||
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
|
||||
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
|
||||
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
|
||||
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
|
||||
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
||||
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
|
||||
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
|
||||
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
||||
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
|
||||
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
|
||||
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
||||
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
|
||||
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
|
||||
0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k)
|
||||
{
|
||||
return tc_aes128_set_encrypt_key(s, k);
|
||||
}
|
||||
|
||||
#define mult8(a)(_double_byte(_double_byte(_double_byte(a))))
|
||||
#define mult9(a)(mult8(a)^(a))
|
||||
#define multb(a)(mult8(a)^_double_byte(a)^(a))
|
||||
#define multd(a)(mult8(a)^_double_byte(_double_byte(a))^(a))
|
||||
#define multe(a)(mult8(a)^_double_byte(_double_byte(a))^_double_byte(a))
|
||||
|
||||
static inline void mult_row_column(uint8_t *out, const uint8_t *in)
|
||||
{
|
||||
out[0] = multe(in[0]) ^ multb(in[1]) ^ multd(in[2]) ^ mult9(in[3]);
|
||||
out[1] = mult9(in[0]) ^ multe(in[1]) ^ multb(in[2]) ^ multd(in[3]);
|
||||
out[2] = multd(in[0]) ^ mult9(in[1]) ^ multe(in[2]) ^ multb(in[3]);
|
||||
out[3] = multb(in[0]) ^ multd(in[1]) ^ mult9(in[2]) ^ multe(in[3]);
|
||||
}
|
||||
|
||||
static inline void inv_mix_columns(uint8_t *s)
|
||||
{
|
||||
uint8_t t[Nb*Nk];
|
||||
|
||||
mult_row_column(t, s);
|
||||
mult_row_column(&t[Nb], s+Nb);
|
||||
mult_row_column(&t[2*Nb], s+(2*Nb));
|
||||
mult_row_column(&t[3*Nb], s+(3*Nb));
|
||||
(void)_copy(s, sizeof(t), t, sizeof(t));
|
||||
}
|
||||
|
||||
static inline void add_round_key(uint8_t *s, const unsigned int *k)
|
||||
{
|
||||
s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
|
||||
s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
|
||||
s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
|
||||
s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
|
||||
s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
|
||||
s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
|
||||
s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
|
||||
s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
|
||||
}
|
||||
|
||||
static inline void inv_sub_bytes(uint8_t *s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < (Nb*Nk); ++i) {
|
||||
s[i] = inv_sbox[s[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This inv_shift_rows also implements the matrix flip required for
|
||||
* inv_mix_columns, but performs it here to reduce the number of memory
|
||||
* operations.
|
||||
*/
|
||||
static inline void inv_shift_rows(uint8_t *s)
|
||||
{
|
||||
uint8_t t[Nb*Nk];
|
||||
|
||||
t[0] = s[0]; t[1] = s[13]; t[2] = s[10]; t[3] = s[7];
|
||||
t[4] = s[4]; t[5] = s[1]; t[6] = s[14]; t[7] = s[11];
|
||||
t[8] = s[8]; t[9] = s[5]; t[10] = s[2]; t[11] = s[15];
|
||||
t[12] = s[12]; t[13] = s[9]; t[14] = s[6]; t[15] = s[3];
|
||||
(void)_copy(s, sizeof(t), t, sizeof(t));
|
||||
}
|
||||
|
||||
int tc_aes_decrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
|
||||
{
|
||||
uint8_t state[Nk*Nb];
|
||||
unsigned int i;
|
||||
|
||||
if (out == (uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (in == (const uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (s == (TCAesKeySched_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
(void)_copy(state, sizeof(state), in, sizeof(state));
|
||||
|
||||
add_round_key(state, s->words + Nb*Nr);
|
||||
|
||||
for (i = Nr - 1; i > 0; --i) {
|
||||
inv_shift_rows(state);
|
||||
inv_sub_bytes(state);
|
||||
add_round_key(state, s->words + Nb*i);
|
||||
inv_mix_columns(state);
|
||||
}
|
||||
|
||||
inv_shift_rows(state);
|
||||
inv_sub_bytes(state);
|
||||
add_round_key(state, s->words);
|
||||
|
||||
(void)_copy(out, sizeof(state), state, sizeof(state));
|
||||
|
||||
/*zeroing out the state buffer */
|
||||
_set(state, TC_ZERO_BYTE, sizeof(state));
|
||||
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
191
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_encrypt.c
Normal file
191
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/aes_encrypt.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/aes.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
|
||||
static const uint8_t sbox[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
|
||||
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
|
||||
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
|
||||
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
|
||||
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
|
||||
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
|
||||
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
|
||||
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
|
||||
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
|
||||
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
|
||||
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
|
||||
0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
static inline unsigned int rotword(unsigned int a)
|
||||
{
|
||||
return (((a) >> 24)|((a) << 8));
|
||||
}
|
||||
|
||||
#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o))
|
||||
#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0))
|
||||
|
||||
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k)
|
||||
{
|
||||
const unsigned int rconst[11] = {
|
||||
0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
||||
0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
|
||||
};
|
||||
unsigned int i;
|
||||
unsigned int t;
|
||||
|
||||
if (s == (TCAesKeySched_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (k == (const uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
for (i = 0; i < Nk; ++i) {
|
||||
s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) |
|
||||
(k[Nb*i+2]<<8) | (k[Nb*i+3]);
|
||||
}
|
||||
|
||||
for (; i < (Nb * (Nr + 1)); ++i) {
|
||||
t = s->words[i-1];
|
||||
if ((i % Nk) == 0) {
|
||||
t = subword(rotword(t)) ^ rconst[i/Nk];
|
||||
}
|
||||
s->words[i] = s->words[i-Nk] ^ t;
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
static inline void add_round_key(uint8_t *s, const unsigned int *k)
|
||||
{
|
||||
s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
|
||||
s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
|
||||
s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
|
||||
s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
|
||||
s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
|
||||
s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
|
||||
s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
|
||||
s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
|
||||
}
|
||||
|
||||
static inline void sub_bytes(uint8_t *s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < (Nb * Nk); ++i) {
|
||||
s[i] = sbox[s[i]];
|
||||
}
|
||||
}
|
||||
|
||||
#define triple(a)(_double_byte(a)^(a))
|
||||
|
||||
static inline void mult_row_column(uint8_t *out, const uint8_t *in)
|
||||
{
|
||||
out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3];
|
||||
out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3];
|
||||
out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]);
|
||||
out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]);
|
||||
}
|
||||
|
||||
static inline void mix_columns(uint8_t *s)
|
||||
{
|
||||
uint8_t t[Nb*Nk];
|
||||
|
||||
mult_row_column(t, s);
|
||||
mult_row_column(&t[Nb], s+Nb);
|
||||
mult_row_column(&t[2 * Nb], s + (2 * Nb));
|
||||
mult_row_column(&t[3 * Nb], s + (3 * Nb));
|
||||
(void) _copy(s, sizeof(t), t, sizeof(t));
|
||||
}
|
||||
|
||||
/*
|
||||
* This shift_rows also implements the matrix flip required for mix_columns, but
|
||||
* performs it here to reduce the number of memory operations.
|
||||
*/
|
||||
static inline void shift_rows(uint8_t *s)
|
||||
{
|
||||
uint8_t t[Nb * Nk];
|
||||
|
||||
t[0] = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15];
|
||||
t[4] = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3];
|
||||
t[8] = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7];
|
||||
t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11];
|
||||
(void) _copy(s, sizeof(t), t, sizeof(t));
|
||||
}
|
||||
|
||||
int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
|
||||
{
|
||||
uint8_t state[Nk*Nb];
|
||||
unsigned int i;
|
||||
|
||||
if (out == (uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (in == (const uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (s == (TCAesKeySched_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
(void)_copy(state, sizeof(state), in, sizeof(state));
|
||||
add_round_key(state, s->words);
|
||||
|
||||
for (i = 0; i < (Nr - 1); ++i) {
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
mix_columns(state);
|
||||
add_round_key(state, s->words + Nb*(i+1));
|
||||
}
|
||||
|
||||
sub_bytes(state);
|
||||
shift_rows(state);
|
||||
add_round_key(state, s->words + Nb*(i+1));
|
||||
|
||||
(void)_copy(out, sizeof(state), state, sizeof(state));
|
||||
|
||||
/* zeroing out the state buffer */
|
||||
_set(state, TC_ZERO_BYTE, sizeof(state));
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
114
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cbc_mode.c
Normal file
114
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cbc_mode.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/* cbc_mode.c - TinyCrypt implementation of CBC mode encryption & decryption */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/cbc_mode.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, const uint8_t *iv,
|
||||
const TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
uint8_t buffer[TC_AES_BLOCK_SIZE];
|
||||
unsigned int n, m;
|
||||
|
||||
/* input sanity check: */
|
||||
if (out == (uint8_t *) 0 ||
|
||||
in == (const uint8_t *) 0 ||
|
||||
sched == (TCAesKeySched_t) 0 ||
|
||||
inlen == 0 ||
|
||||
outlen == 0 ||
|
||||
(inlen % TC_AES_BLOCK_SIZE) != 0 ||
|
||||
(outlen % TC_AES_BLOCK_SIZE) != 0 ||
|
||||
outlen != inlen + TC_AES_BLOCK_SIZE) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* copy iv to the buffer */
|
||||
(void)_copy(buffer, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE);
|
||||
/* copy iv to the output buffer */
|
||||
(void)_copy(out, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE);
|
||||
out += TC_AES_BLOCK_SIZE;
|
||||
|
||||
for (n = m = 0; n < inlen; ++n) {
|
||||
buffer[m++] ^= *in++;
|
||||
if (m == TC_AES_BLOCK_SIZE) {
|
||||
(void)tc_aes_encrypt(buffer, buffer, sched);
|
||||
(void)_copy(out, TC_AES_BLOCK_SIZE,
|
||||
buffer, TC_AES_BLOCK_SIZE);
|
||||
out += TC_AES_BLOCK_SIZE;
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, const uint8_t *iv,
|
||||
const TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
uint8_t buffer[TC_AES_BLOCK_SIZE];
|
||||
const uint8_t *p;
|
||||
unsigned int n, m;
|
||||
|
||||
/* sanity check the inputs */
|
||||
if (out == (uint8_t *) 0 ||
|
||||
in == (const uint8_t *) 0 ||
|
||||
sched == (TCAesKeySched_t) 0 ||
|
||||
inlen == 0 ||
|
||||
outlen == 0 ||
|
||||
(inlen % TC_AES_BLOCK_SIZE) != 0 ||
|
||||
(outlen % TC_AES_BLOCK_SIZE) != 0 ||
|
||||
outlen != inlen - TC_AES_BLOCK_SIZE) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that in == iv + ciphertext, i.e. the iv and the ciphertext are
|
||||
* contiguous. This allows for a very efficient decryption algorithm
|
||||
* that would not otherwise be possible.
|
||||
*/
|
||||
p = iv;
|
||||
for (n = m = 0; n < inlen; ++n) {
|
||||
if ((n % TC_AES_BLOCK_SIZE) == 0) {
|
||||
(void)tc_aes_decrypt(buffer, in, sched);
|
||||
in += TC_AES_BLOCK_SIZE;
|
||||
m = 0;
|
||||
}
|
||||
*out++ = buffer[m++] ^ *p++;
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
266
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ccm_mode.c
Normal file
266
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ccm_mode.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/* ccm_mode.c - TinyCrypt implementation of CCM mode */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/ccm_mode.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
|
||||
unsigned int nlen, unsigned int mlen)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (c == (TCCcmMode_t) 0 ||
|
||||
sched == (TCAesKeySched_t) 0 ||
|
||||
nonce == (uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (nlen != 13) {
|
||||
return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/
|
||||
} else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) {
|
||||
return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/
|
||||
}
|
||||
|
||||
c->mlen = mlen;
|
||||
c->sched = sched;
|
||||
c->nonce = nonce;
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of CBC-MAC mode used in CCM.
|
||||
*/
|
||||
static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen,
|
||||
unsigned int flag, TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
|
||||
if (flag > 0) {
|
||||
T[0] ^= (uint8_t)(dlen >> 8);
|
||||
T[1] ^= (uint8_t)(dlen);
|
||||
dlen += 2; i = 2;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
while (i < dlen) {
|
||||
T[i++ % (Nb * Nk)] ^= *data++;
|
||||
if (((i % (Nb * Nk)) == 0) || dlen == i) {
|
||||
(void) tc_aes_encrypt(T, T, sched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation of CTR mode used in CCM.
|
||||
* The CTR mode used by CCM is slightly different than the conventional CTR
|
||||
* mode (the counter is increased before encryption, instead of after
|
||||
* encryption). Besides, it is assumed that the counter is stored in the last
|
||||
* 2 bytes of the nonce.
|
||||
*/
|
||||
static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
uint8_t buffer[TC_AES_BLOCK_SIZE];
|
||||
uint8_t nonce[TC_AES_BLOCK_SIZE];
|
||||
uint16_t block_num;
|
||||
unsigned int i;
|
||||
|
||||
/* input sanity check: */
|
||||
if (out == (uint8_t *) 0 ||
|
||||
in == (uint8_t *) 0 ||
|
||||
ctr == (uint8_t *) 0 ||
|
||||
sched == (TCAesKeySched_t) 0 ||
|
||||
inlen == 0 ||
|
||||
outlen == 0 ||
|
||||
outlen != inlen) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* copy the counter to the nonce */
|
||||
(void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
|
||||
|
||||
/* select the last 2 bytes of the nonce to be incremented */
|
||||
block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15]));
|
||||
for (i = 0; i < inlen; ++i) {
|
||||
if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
|
||||
block_num++;
|
||||
nonce[14] = (uint8_t)(block_num >> 8);
|
||||
nonce[15] = (uint8_t)(block_num);
|
||||
if (!tc_aes_encrypt(buffer, nonce, sched)) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
}
|
||||
/* update the output */
|
||||
*out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
|
||||
}
|
||||
|
||||
/* update the counter */
|
||||
ctr[14] = nonce[14]; ctr[15] = nonce[15];
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
|
||||
const uint8_t *associated_data,
|
||||
unsigned int alen, const uint8_t *payload,
|
||||
unsigned int plen, TCCcmMode_t c)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if ((out == (uint8_t *) 0) ||
|
||||
(c == (TCCcmMode_t) 0) ||
|
||||
((plen > 0) && (payload == (uint8_t *) 0)) ||
|
||||
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
|
||||
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
|
||||
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
|
||||
(olen < (plen + c->mlen))) { /* invalid output buffer size */
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
uint8_t b[Nb * Nk];
|
||||
uint8_t tag[Nb * Nk];
|
||||
unsigned int i;
|
||||
|
||||
/* GENERATING THE AUTHENTICATION TAG: */
|
||||
|
||||
/* formatting the sequence b for authentication: */
|
||||
b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
|
||||
for (i = 1; i <= 13; ++i) {
|
||||
b[i] = c->nonce[i - 1];
|
||||
}
|
||||
b[14] = (uint8_t)(plen >> 8);
|
||||
b[15] = (uint8_t)(plen);
|
||||
|
||||
/* computing the authentication tag using cbc-mac: */
|
||||
(void) tc_aes_encrypt(tag, b, c->sched);
|
||||
if (alen > 0) {
|
||||
ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
|
||||
}
|
||||
if (plen > 0) {
|
||||
ccm_cbc_mac(tag, payload, plen, 0, c->sched);
|
||||
}
|
||||
|
||||
/* ENCRYPTION: */
|
||||
|
||||
/* formatting the sequence b for encryption: */
|
||||
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
|
||||
b[14] = b[15] = TC_ZERO_BYTE;
|
||||
|
||||
/* encrypting payload using ctr mode: */
|
||||
ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
|
||||
|
||||
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/
|
||||
|
||||
/* encrypting b and adding the tag to the output: */
|
||||
(void) tc_aes_encrypt(b, b, c->sched);
|
||||
out += plen;
|
||||
for (i = 0; i < c->mlen; ++i) {
|
||||
*out++ = tag[i] ^ b[i];
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
|
||||
const uint8_t *associated_data,
|
||||
unsigned int alen, const uint8_t *payload,
|
||||
unsigned int plen, TCCcmMode_t c)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if ((out == (uint8_t *) 0) ||
|
||||
(c == (TCCcmMode_t) 0) ||
|
||||
((plen > 0) && (payload == (uint8_t *) 0)) ||
|
||||
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
|
||||
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
|
||||
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
|
||||
(olen < plen - c->mlen)) { /* invalid output buffer size */
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
uint8_t b[Nb * Nk];
|
||||
uint8_t tag[Nb * Nk];
|
||||
unsigned int i;
|
||||
|
||||
/* DECRYPTION: */
|
||||
|
||||
/* formatting the sequence b for decryption: */
|
||||
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
|
||||
for (i = 1; i < 14; ++i) {
|
||||
b[i] = c->nonce[i - 1];
|
||||
}
|
||||
b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
|
||||
|
||||
/* decrypting payload using ctr mode: */
|
||||
ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
|
||||
|
||||
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
|
||||
|
||||
/* encrypting b and restoring the tag from input: */
|
||||
(void) tc_aes_encrypt(b, b, c->sched);
|
||||
for (i = 0; i < c->mlen; ++i) {
|
||||
tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
|
||||
}
|
||||
|
||||
/* VERIFYING THE AUTHENTICATION TAG: */
|
||||
|
||||
/* formatting the sequence b for authentication: */
|
||||
b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
|
||||
for (i = 1; i < 14; ++i) {
|
||||
b[i] = c->nonce[i - 1];
|
||||
}
|
||||
b[14] = (uint8_t)((plen - c->mlen) >> 8);
|
||||
b[15] = (uint8_t)(plen - c->mlen);
|
||||
|
||||
/* computing the authentication tag using cbc-mac: */
|
||||
(void) tc_aes_encrypt(b, b, c->sched);
|
||||
if (alen > 0) {
|
||||
ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
|
||||
}
|
||||
if (plen > 0) {
|
||||
ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
|
||||
}
|
||||
|
||||
/* comparing the received tag and the computed one: */
|
||||
if (_compare(b, tag, c->mlen) == 0) {
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
} else {
|
||||
/* erase the decrypted buffer in case of mac validation failure: */
|
||||
_set(out, 0, plen - c->mlen);
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
}
|
||||
254
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cmac_mode.c
Normal file
254
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/cmac_mode.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/* cmac_mode.c - TinyCrypt CMAC mode implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/aes.h"
|
||||
#include "../include/tinycrypt/cmac_mode.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
/* max number of calls until change the key (2^48).*/
|
||||
const static uint64_t MAX_CALLS = ((uint64_t)1 << 48);
|
||||
|
||||
/*
|
||||
* gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte
|
||||
* array with byte 0 the most significant and byte 15 the least significant.
|
||||
* High bit carry reduction is based on the primitive polynomial
|
||||
*
|
||||
* X^128 + X^7 + X^2 + X + 1,
|
||||
*
|
||||
* which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed,
|
||||
* since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since
|
||||
* addition of polynomials with coefficients in Z/Z(2) is just XOR, we can
|
||||
* add X^128 to both sides to get
|
||||
*
|
||||
* X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1)
|
||||
*
|
||||
* and the coefficients of the polynomial on the right hand side form the
|
||||
* string 1000 0111 = 0x87, which is the value of gf_wrap.
|
||||
*
|
||||
* This gets used in the following way. Doubling in GF(2^128) is just a left
|
||||
* shift by 1 bit, except when the most significant bit is 1. In the latter
|
||||
* case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit
|
||||
* that overflows beyond 128 bits can be replaced by addition of
|
||||
* X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition
|
||||
* in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87
|
||||
* into the low order byte after a left shift when the starting high order
|
||||
* bit is 1.
|
||||
*/
|
||||
const unsigned char gf_wrap = 0x87;
|
||||
|
||||
/*
|
||||
* assumes: out != NULL and points to a GF(2^n) value to receive the
|
||||
* doubled value;
|
||||
* in != NULL and points to a 16 byte GF(2^n) value
|
||||
* to double;
|
||||
* the in and out buffers do not overlap.
|
||||
* effects: doubles the GF(2^n) value pointed to by "in" and places
|
||||
* the result in the GF(2^n) value pointed to by "out."
|
||||
*/
|
||||
void gf_double(uint8_t *out, uint8_t *in)
|
||||
{
|
||||
|
||||
/* start with low order byte */
|
||||
uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1);
|
||||
|
||||
/* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */
|
||||
uint8_t carry = (in[0] >> 7) ? gf_wrap : 0;
|
||||
|
||||
out += (TC_AES_BLOCK_SIZE - 1);
|
||||
for (;;) {
|
||||
*out-- = (*x << 1) ^ carry;
|
||||
if (x == in) {
|
||||
break;
|
||||
}
|
||||
carry = *x-- >> 7;
|
||||
}
|
||||
}
|
||||
|
||||
int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (s == (TCCmacState_t) 0 ||
|
||||
key == (const uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* put s into a known state */
|
||||
_set(s, 0, sizeof(*s));
|
||||
s->sched = sched;
|
||||
|
||||
/* configure the encryption key used by the underlying block cipher */
|
||||
tc_aes128_set_encrypt_key(s->sched, key);
|
||||
|
||||
/* compute s->K1 and s->K2 from s->iv using s->keyid */
|
||||
_set(s->iv, 0, TC_AES_BLOCK_SIZE);
|
||||
tc_aes_encrypt(s->iv, s->iv, s->sched);
|
||||
gf_double (s->K1, s->iv);
|
||||
gf_double (s->K2, s->K1);
|
||||
|
||||
/* reset s->iv to 0 in case someone wants to compute now */
|
||||
tc_cmac_init(s);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_cmac_erase(TCCmacState_t s)
|
||||
{
|
||||
if (s == (TCCmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* destroy the current state */
|
||||
_set(s, 0, sizeof(*s));
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_cmac_init(TCCmacState_t s)
|
||||
{
|
||||
/* input sanity check: */
|
||||
if (s == (TCCmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* CMAC starts with an all zero initialization vector */
|
||||
_set(s->iv, 0, TC_AES_BLOCK_SIZE);
|
||||
|
||||
/* and the leftover buffer is empty */
|
||||
_set(s->leftover, 0, TC_AES_BLOCK_SIZE);
|
||||
s->leftover_offset = 0;
|
||||
|
||||
/* Set countdown to max number of calls allowed before re-keying: */
|
||||
s->countdown = MAX_CALLS;
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* input sanity check: */
|
||||
if (s == (TCCmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
if (data_length == 0) {
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
if (data == (const uint8_t *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
if (s->countdown == 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
s->countdown--;
|
||||
|
||||
if (s->leftover_offset > 0) {
|
||||
/* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */
|
||||
size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset;
|
||||
|
||||
if (data_length < remaining_space) {
|
||||
/* still not enough data to encrypt this time either */
|
||||
_copy(&s->leftover[s->leftover_offset], data_length, data, data_length);
|
||||
s->leftover_offset += data_length;
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
/* leftover block is now full; encrypt it first */
|
||||
_copy(&s->leftover[s->leftover_offset],
|
||||
remaining_space,
|
||||
data,
|
||||
remaining_space);
|
||||
data_length -= remaining_space;
|
||||
data += remaining_space;
|
||||
s->leftover_offset = 0;
|
||||
|
||||
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
|
||||
s->iv[i] ^= s->leftover[i];
|
||||
}
|
||||
tc_aes_encrypt(s->iv, s->iv, s->sched);
|
||||
}
|
||||
|
||||
/* CBC encrypt each (except the last) of the data blocks */
|
||||
while (data_length > TC_AES_BLOCK_SIZE) {
|
||||
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
|
||||
s->iv[i] ^= data[i];
|
||||
}
|
||||
tc_aes_encrypt(s->iv, s->iv, s->sched);
|
||||
data += TC_AES_BLOCK_SIZE;
|
||||
data_length -= TC_AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (data_length > 0) {
|
||||
/* save leftover data for next time */
|
||||
_copy(s->leftover, data_length, data, data_length);
|
||||
s->leftover_offset = data_length;
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_cmac_final(uint8_t *tag, TCCmacState_t s)
|
||||
{
|
||||
uint8_t *k;
|
||||
unsigned int i;
|
||||
|
||||
/* input sanity check: */
|
||||
if (tag == (uint8_t *) 0 ||
|
||||
s == (TCCmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
if (s->leftover_offset == TC_AES_BLOCK_SIZE) {
|
||||
/* the last message block is a full-sized block */
|
||||
k = (uint8_t *) s->K1;
|
||||
} else {
|
||||
/* the final message block is not a full-sized block */
|
||||
size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset;
|
||||
|
||||
_set(&s->leftover[s->leftover_offset], 0, remaining);
|
||||
s->leftover[s->leftover_offset] = TC_CMAC_PADDING;
|
||||
k = (uint8_t *) s->K2;
|
||||
}
|
||||
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
|
||||
s->iv[i] ^= s->leftover[i] ^ k[i];
|
||||
}
|
||||
|
||||
tc_aes_encrypt(tag, s->iv, s->sched);
|
||||
|
||||
/* erasing state: */
|
||||
tc_cmac_erase(s);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
85
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_mode.c
Normal file
85
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_mode.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* ctr_mode.c - TinyCrypt CTR mode implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/ctr_mode.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
||||
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
|
||||
{
|
||||
|
||||
uint8_t buffer[TC_AES_BLOCK_SIZE];
|
||||
uint8_t nonce[TC_AES_BLOCK_SIZE];
|
||||
unsigned int block_num;
|
||||
unsigned int i;
|
||||
|
||||
/* input sanity check: */
|
||||
if (out == (uint8_t *) 0 ||
|
||||
in == (uint8_t *) 0 ||
|
||||
ctr == (uint8_t *) 0 ||
|
||||
sched == (TCAesKeySched_t) 0 ||
|
||||
inlen == 0 ||
|
||||
outlen == 0 ||
|
||||
outlen != inlen) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* copy the ctr to the nonce */
|
||||
(void)_copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
|
||||
|
||||
/* select the last 4 bytes of the nonce to be incremented */
|
||||
block_num = (nonce[12] << 24) | (nonce[13] << 16) |
|
||||
(nonce[14] << 8) | (nonce[15]);
|
||||
for (i = 0; i < inlen; ++i) {
|
||||
if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
|
||||
/* encrypt data using the current nonce */
|
||||
if (tc_aes_encrypt(buffer, nonce, sched)) {
|
||||
block_num++;
|
||||
nonce[12] = (uint8_t)(block_num >> 24);
|
||||
nonce[13] = (uint8_t)(block_num >> 16);
|
||||
nonce[14] = (uint8_t)(block_num >> 8);
|
||||
nonce[15] = (uint8_t)(block_num);
|
||||
} else {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
}
|
||||
/* update the output */
|
||||
*out++ = buffer[i%(TC_AES_BLOCK_SIZE)] ^ *in++;
|
||||
}
|
||||
|
||||
/* update the counter */
|
||||
ctr[12] = nonce[12]; ctr[13] = nonce[13];
|
||||
ctr[14] = nonce[14]; ctr[15] = nonce[15];
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
283
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_prng.c
Normal file
283
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ctr_prng.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016, Chris Morrison
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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 "../include/tinycrypt/ctr_prng.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* This PRNG is based on the CTR_DRBG described in Recommendation for Random
|
||||
* Number Generation Using Deterministic Random Bit Generators,
|
||||
* NIST SP 800-90A Rev. 1.
|
||||
*
|
||||
* Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
|
||||
* described in that document.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Array incrementer
|
||||
* Treats the supplied array as one contiguous number (MSB in arr[0]), and
|
||||
* increments it by one
|
||||
* @return none
|
||||
* @param arr IN/OUT -- array to be incremented
|
||||
* @param len IN -- size of arr in bytes
|
||||
*/
|
||||
static void arrInc(uint8_t arr[], unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
if (0 != arr) {
|
||||
for (i = len; i > 0U; i--) {
|
||||
if (++arr[i-1] != 0U) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CTR PRNG update
|
||||
* Updates the internal state of supplied the CTR PRNG context
|
||||
* increments it by one
|
||||
* @return none
|
||||
* @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
|
||||
* @param ctx IN/OUT -- CTR PRNG state
|
||||
* @param providedData IN -- data used when updating the internal state
|
||||
*/
|
||||
static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
|
||||
{
|
||||
if (0 != ctx) {
|
||||
/* 10.2.1.2 step 1 */
|
||||
uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
|
||||
unsigned int len = 0U;
|
||||
|
||||
/* 10.2.1.2 step 2 */
|
||||
while (len < sizeof temp) {
|
||||
unsigned int blocklen = sizeof(temp) - len;
|
||||
uint8_t output_block[TC_AES_BLOCK_SIZE];
|
||||
|
||||
/* 10.2.1.2 step 2.1 */
|
||||
arrInc(ctx->V, sizeof ctx->V);
|
||||
|
||||
/* 10.2.1.2 step 2.2 */
|
||||
if (blocklen > TC_AES_BLOCK_SIZE) {
|
||||
blocklen = TC_AES_BLOCK_SIZE;
|
||||
}
|
||||
(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
|
||||
|
||||
/* 10.2.1.2 step 2.3/step 3 */
|
||||
memcpy(&(temp[len]), output_block, blocklen);
|
||||
|
||||
len += blocklen;
|
||||
}
|
||||
|
||||
/* 10.2.1.2 step 4 */
|
||||
if (0 != providedData) {
|
||||
unsigned int i;
|
||||
for (i = 0U; i < sizeof temp; i++) {
|
||||
temp[i] ^= providedData[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* 10.2.1.2 step 5 */
|
||||
(void)tc_aes128_set_encrypt_key(&ctx->key, temp);
|
||||
|
||||
/* 10.2.1.2 step 6 */
|
||||
memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const entropy,
|
||||
unsigned int entropyLen,
|
||||
uint8_t const * const personalization,
|
||||
unsigned int pLen)
|
||||
{
|
||||
int result = TC_CRYPTO_FAIL;
|
||||
unsigned int i;
|
||||
uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
|
||||
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
|
||||
uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
|
||||
|
||||
if (0 != personalization) {
|
||||
/* 10.2.1.3.1 step 1 */
|
||||
unsigned int len = pLen;
|
||||
if (len > sizeof personalization_buf) {
|
||||
len = sizeof personalization_buf;
|
||||
}
|
||||
|
||||
/* 10.2.1.3.1 step 2 */
|
||||
memcpy(personalization_buf, personalization, len);
|
||||
}
|
||||
|
||||
if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
|
||||
/* 10.2.1.3.1 step 3 */
|
||||
memcpy(seed_material, entropy, sizeof seed_material);
|
||||
for (i = 0U; i < sizeof seed_material; i++) {
|
||||
seed_material[i] ^= personalization_buf[i];
|
||||
}
|
||||
|
||||
/* 10.2.1.3.1 step 4 */
|
||||
(void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
|
||||
|
||||
/* 10.2.1.3.1 step 5 */
|
||||
memset(ctx->V, 0x00, sizeof ctx->V);
|
||||
|
||||
/* 10.2.1.3.1 step 6 */
|
||||
tc_ctr_prng_update(ctx, seed_material);
|
||||
|
||||
/* 10.2.1.3.1 step 7 */
|
||||
ctx->reseedCount = 1U;
|
||||
|
||||
result = TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const entropy,
|
||||
unsigned int entropyLen,
|
||||
uint8_t const * const additional_input,
|
||||
unsigned int additionallen)
|
||||
{
|
||||
unsigned int i;
|
||||
int result = TC_CRYPTO_FAIL;
|
||||
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
|
||||
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
|
||||
|
||||
if (0 != additional_input) {
|
||||
/* 10.2.1.4.1 step 1 */
|
||||
unsigned int len = additionallen;
|
||||
if (len > sizeof additional_input_buf) {
|
||||
len = sizeof additional_input_buf;
|
||||
}
|
||||
|
||||
/* 10.2.1.4.1 step 2 */
|
||||
memcpy(additional_input_buf, additional_input, len);
|
||||
}
|
||||
|
||||
unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
|
||||
if ((0 != ctx) && (entropyLen >= seedlen)) {
|
||||
/* 10.2.1.4.1 step 3 */
|
||||
memcpy(seed_material, entropy, sizeof seed_material);
|
||||
for (i = 0U; i < sizeof seed_material; i++) {
|
||||
seed_material[i] ^= additional_input_buf[i];
|
||||
}
|
||||
|
||||
/* 10.2.1.4.1 step 4 */
|
||||
tc_ctr_prng_update(ctx, seed_material);
|
||||
|
||||
/* 10.2.1.4.1 step 5 */
|
||||
ctx->reseedCount = 1U;
|
||||
|
||||
result = TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
|
||||
uint8_t const * const additional_input,
|
||||
unsigned int additionallen,
|
||||
uint8_t * const out,
|
||||
unsigned int outlen)
|
||||
{
|
||||
/* 2^48 - see section 10.2.1 */
|
||||
static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
|
||||
|
||||
/* 2^19 bits - see section 10.2.1 */
|
||||
static const unsigned int MAX_BYTES_PER_REQ = 65536U;
|
||||
|
||||
unsigned int result = TC_CRYPTO_FAIL;
|
||||
|
||||
if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
|
||||
/* 10.2.1.5.1 step 1 */
|
||||
if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
|
||||
result = TC_CTR_PRNG_RESEED_REQ;
|
||||
} else {
|
||||
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
|
||||
if (0 != additional_input) {
|
||||
/* 10.2.1.5.1 step 2 */
|
||||
unsigned int len = additionallen;
|
||||
if (len > sizeof additional_input_buf) {
|
||||
len = sizeof additional_input_buf;
|
||||
}
|
||||
memcpy(additional_input_buf, additional_input, len);
|
||||
tc_ctr_prng_update(ctx, additional_input_buf);
|
||||
}
|
||||
|
||||
/* 10.2.1.5.1 step 3 - implicit */
|
||||
|
||||
/* 10.2.1.5.1 step 4 */
|
||||
unsigned int len = 0U;
|
||||
while (len < outlen) {
|
||||
unsigned int blocklen = outlen - len;
|
||||
uint8_t output_block[TC_AES_BLOCK_SIZE];
|
||||
|
||||
/* 10.2.1.5.1 step 4.1 */
|
||||
arrInc(ctx->V, sizeof ctx->V);
|
||||
|
||||
/* 10.2.1.5.1 step 4.2 */
|
||||
(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
|
||||
|
||||
/* 10.2.1.5.1 step 4.3/step 5 */
|
||||
if (blocklen > TC_AES_BLOCK_SIZE) {
|
||||
blocklen = TC_AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(&(out[len]), output_block, blocklen);
|
||||
|
||||
len += blocklen;
|
||||
}
|
||||
|
||||
/* 10.2.1.5.1 step 6 */
|
||||
tc_ctr_prng_update(ctx, additional_input_buf);
|
||||
|
||||
/* 10.2.1.5.1 step 7 */
|
||||
ctx->reseedCount++;
|
||||
|
||||
/* 10.2.1.5.1 step 8 */
|
||||
result = TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
|
||||
{
|
||||
if (0 != ctx) {
|
||||
memset(ctx->key.words, 0x00, sizeof ctx->key.words);
|
||||
memset(ctx->V, 0x00, sizeof ctx->V);
|
||||
ctx->reseedCount = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
942
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc.c
Normal file
942
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc.c
Normal file
@@ -0,0 +1,942 @@
|
||||
/* ecc.c - TinyCrypt implementation of common ECC functions */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/ecc.h"
|
||||
#include "../include/tinycrypt/ecc_platform_specific.h"
|
||||
#include <string.h>
|
||||
|
||||
/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
|
||||
* has access to enough entropy in order to feed the PRNG regularly. */
|
||||
#if default_RNG_defined
|
||||
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
|
||||
#else
|
||||
static uECC_RNG_Function g_rng_function = 0;
|
||||
#endif
|
||||
|
||||
void uECC_set_rng(uECC_RNG_Function rng_function)
|
||||
{
|
||||
g_rng_function = rng_function;
|
||||
}
|
||||
|
||||
uECC_RNG_Function uECC_get_rng(void)
|
||||
{
|
||||
return g_rng_function;
|
||||
}
|
||||
|
||||
int uECC_curve_private_key_size(uECC_Curve curve)
|
||||
{
|
||||
return BITS_TO_BYTES(curve->num_n_bits);
|
||||
}
|
||||
|
||||
int uECC_curve_public_key_size(uECC_Curve curve)
|
||||
{
|
||||
return 2 * curve->num_bytes;
|
||||
}
|
||||
|
||||
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words)
|
||||
{
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
vli[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t bits = 0;
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
bits |= vli[i];
|
||||
}
|
||||
return (bits == 0);
|
||||
}
|
||||
|
||||
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
|
||||
{
|
||||
return (vli[bit >> uECC_WORD_BITS_SHIFT] &
|
||||
((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
|
||||
}
|
||||
|
||||
/* Counts the number of words in vli. */
|
||||
static wordcount_t vli_numDigits(const uECC_word_t *vli,
|
||||
const wordcount_t max_words)
|
||||
{
|
||||
|
||||
wordcount_t i;
|
||||
/* Search from the end until we find a non-zero digit. We do it in reverse
|
||||
* because we expect that most digits will be nonzero. */
|
||||
for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
|
||||
}
|
||||
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
|
||||
const wordcount_t max_words)
|
||||
{
|
||||
|
||||
uECC_word_t i;
|
||||
uECC_word_t digit;
|
||||
|
||||
wordcount_t num_digits = vli_numDigits(vli, max_words);
|
||||
if (num_digits == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
digit = vli[num_digits - 1];
|
||||
for (i = 0; digit; ++i) {
|
||||
digit >>= 1;
|
||||
}
|
||||
|
||||
return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
|
||||
}
|
||||
|
||||
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
wordcount_t i;
|
||||
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
|
||||
const uECC_word_t *right,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
wordcount_t i;
|
||||
|
||||
for (i = num_words - 1; i >= 0; --i) {
|
||||
if (left[i] > right[i]) {
|
||||
return 1;
|
||||
} else if (left[i] < right[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
|
||||
uECC_word_t diff = 0;
|
||||
wordcount_t i;
|
||||
|
||||
for (i = num_words - 1; i >= 0; --i) {
|
||||
diff |= (left[i] ^ right[i]);
|
||||
}
|
||||
return !(diff == 0);
|
||||
}
|
||||
|
||||
uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
|
||||
{
|
||||
return (p_true*(cond)) | (p_false*(!cond));
|
||||
}
|
||||
|
||||
/* Computes result = left - right, returning borrow, in constant time.
|
||||
* Can modify in place. */
|
||||
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t borrow = 0;
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
uECC_word_t diff = left[i] - right[i] - borrow;
|
||||
uECC_word_t val = (diff > left[i]);
|
||||
borrow = cond_set(val, borrow, (diff != left[i]));
|
||||
|
||||
result[i] = diff;
|
||||
}
|
||||
return borrow;
|
||||
}
|
||||
|
||||
/* Computes result = left + right, returning carry, in constant time.
|
||||
* Can modify in place. */
|
||||
static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t carry = 0;
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_words; ++i) {
|
||||
uECC_word_t sum = left[i] + right[i] + carry;
|
||||
uECC_word_t val = (sum < left[i]);
|
||||
carry = cond_set(val, carry, (sum != left[i]));
|
||||
result[i] = sum;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t tmp[NUM_ECC_WORDS];
|
||||
uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words);
|
||||
uECC_word_t equal = uECC_vli_isZero(tmp, num_words);
|
||||
return (!equal - 2 * neg);
|
||||
}
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t *end = vli;
|
||||
uECC_word_t carry = 0;
|
||||
|
||||
vli += num_words;
|
||||
while (vli-- > end) {
|
||||
uECC_word_t temp = *vli;
|
||||
*vli = (temp >> 1) | carry;
|
||||
carry = temp << (uECC_WORD_BITS - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
|
||||
uECC_word_t *r1, uECC_word_t *r2)
|
||||
{
|
||||
|
||||
uECC_dword_t p = (uECC_dword_t)a * b;
|
||||
uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
|
||||
r01 += p;
|
||||
*r2 += (r01 < p);
|
||||
*r1 = r01 >> uECC_WORD_BITS;
|
||||
*r0 = (uECC_word_t)r01;
|
||||
|
||||
}
|
||||
|
||||
/* Computes result = left * right. Result must be 2 * num_words long. */
|
||||
static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words)
|
||||
{
|
||||
|
||||
uECC_word_t r0 = 0;
|
||||
uECC_word_t r1 = 0;
|
||||
uECC_word_t r2 = 0;
|
||||
wordcount_t i, k;
|
||||
|
||||
/* Compute each digit of result in sequence, maintaining the carries. */
|
||||
for (k = 0; k < num_words; ++k) {
|
||||
|
||||
for (i = 0; i <= k; ++i) {
|
||||
muladd(left[i], right[k - i], &r0, &r1, &r2);
|
||||
}
|
||||
|
||||
result[k] = r0;
|
||||
r0 = r1;
|
||||
r1 = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
for (k = num_words; k < num_words * 2 - 1; ++k) {
|
||||
|
||||
for (i = (k + 1) - num_words; i < num_words; ++i) {
|
||||
muladd(left[i], right[k - i], &r0, &r1, &r2);
|
||||
}
|
||||
result[k] = r0;
|
||||
r0 = r1;
|
||||
r1 = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
result[num_words * 2 - 1] = r0;
|
||||
}
|
||||
|
||||
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t carry = uECC_vli_add(result, left, right, num_words);
|
||||
if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {
|
||||
/* result > mod (result = mod + remainder), so subtract mod to get
|
||||
* remainder. */
|
||||
uECC_vli_sub(result, result, mod, num_words);
|
||||
}
|
||||
}
|
||||
|
||||
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);
|
||||
if (l_borrow) {
|
||||
/* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
|
||||
* we can get the correct result from result + mod (with overflow). */
|
||||
uECC_vli_add(result, result, mod, num_words);
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes result = product % mod, where product is 2N words long. */
|
||||
/* Currently only designed to work for curve_p or curve_n. */
|
||||
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
|
||||
const uECC_word_t *mod, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
|
||||
uECC_word_t tmp[2 * NUM_ECC_WORDS];
|
||||
uECC_word_t *v[2] = {tmp, product};
|
||||
uECC_word_t index;
|
||||
|
||||
/* Shift mod so its highest set bit is at the maximum position. */
|
||||
bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
|
||||
uECC_vli_numBits(mod, num_words);
|
||||
wordcount_t word_shift = shift / uECC_WORD_BITS;
|
||||
wordcount_t bit_shift = shift % uECC_WORD_BITS;
|
||||
uECC_word_t carry = 0;
|
||||
uECC_vli_clear(mod_multiple, word_shift);
|
||||
if (bit_shift > 0) {
|
||||
for(index = 0; index < (uECC_word_t)num_words; ++index) {
|
||||
mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
|
||||
carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
|
||||
}
|
||||
} else {
|
||||
uECC_vli_set(mod_multiple + word_shift, mod, num_words);
|
||||
}
|
||||
|
||||
for (index = 1; shift >= 0; --shift) {
|
||||
uECC_word_t borrow = 0;
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_words * 2; ++i) {
|
||||
uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
|
||||
if (diff != v[index][i]) {
|
||||
borrow = (diff > v[index][i]);
|
||||
}
|
||||
v[1 - index][i] = diff;
|
||||
}
|
||||
/* Swap the index if there was no borrow */
|
||||
index = !(index ^ borrow);
|
||||
uECC_vli_rshift1(mod_multiple, num_words);
|
||||
mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
|
||||
(uECC_WORD_BITS - 1);
|
||||
uECC_vli_rshift1(mod_multiple + num_words, num_words);
|
||||
}
|
||||
uECC_vli_set(result, v[index], num_words);
|
||||
}
|
||||
|
||||
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t product[2 * NUM_ECC_WORDS];
|
||||
uECC_vli_mult(product, left, right, num_words);
|
||||
uECC_vli_mmod(result, product, mod, num_words);
|
||||
}
|
||||
|
||||
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t product[2 * NUM_ECC_WORDS];
|
||||
uECC_vli_mult(product, left, right, curve->num_words);
|
||||
|
||||
curve->mmod_fast(result, product);
|
||||
}
|
||||
|
||||
static void uECC_vli_modSquare_fast(uECC_word_t *result,
|
||||
const uECC_word_t *left,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
uECC_vli_modMult_fast(result, left, left, curve);
|
||||
}
|
||||
|
||||
|
||||
#define EVEN(vli) (!(vli[0] & 1))
|
||||
|
||||
static void vli_modInv_update(uECC_word_t *uv,
|
||||
const uECC_word_t *mod,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
|
||||
uECC_word_t carry = 0;
|
||||
|
||||
if (!EVEN(uv)) {
|
||||
carry = uECC_vli_add(uv, uv, mod, num_words);
|
||||
}
|
||||
uECC_vli_rshift1(uv, num_words);
|
||||
if (carry) {
|
||||
uv[num_words - 1] |= HIGH_BIT_SET;
|
||||
}
|
||||
}
|
||||
|
||||
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
|
||||
const uECC_word_t *mod, wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
|
||||
uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
|
||||
cmpresult_t cmpResult;
|
||||
|
||||
if (uECC_vli_isZero(input, num_words)) {
|
||||
uECC_vli_clear(result, num_words);
|
||||
return;
|
||||
}
|
||||
|
||||
uECC_vli_set(a, input, num_words);
|
||||
uECC_vli_set(b, mod, num_words);
|
||||
uECC_vli_clear(u, num_words);
|
||||
u[0] = 1;
|
||||
uECC_vli_clear(v, num_words);
|
||||
while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {
|
||||
if (EVEN(a)) {
|
||||
uECC_vli_rshift1(a, num_words);
|
||||
vli_modInv_update(u, mod, num_words);
|
||||
} else if (EVEN(b)) {
|
||||
uECC_vli_rshift1(b, num_words);
|
||||
vli_modInv_update(v, mod, num_words);
|
||||
} else if (cmpResult > 0) {
|
||||
uECC_vli_sub(a, a, b, num_words);
|
||||
uECC_vli_rshift1(a, num_words);
|
||||
if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {
|
||||
uECC_vli_add(u, u, mod, num_words);
|
||||
}
|
||||
uECC_vli_sub(u, u, v, num_words);
|
||||
vli_modInv_update(u, mod, num_words);
|
||||
} else {
|
||||
uECC_vli_sub(b, b, a, num_words);
|
||||
uECC_vli_rshift1(b, num_words);
|
||||
if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {
|
||||
uECC_vli_add(v, v, mod, num_words);
|
||||
}
|
||||
uECC_vli_sub(v, v, u, num_words);
|
||||
vli_modInv_update(v, mod, num_words);
|
||||
}
|
||||
}
|
||||
uECC_vli_set(result, u, num_words);
|
||||
}
|
||||
|
||||
/* ------ Point operations ------ */
|
||||
|
||||
void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
|
||||
uECC_word_t * Z1, uECC_Curve curve)
|
||||
{
|
||||
/* t1 = X, t2 = Y, t3 = Z */
|
||||
uECC_word_t t4[NUM_ECC_WORDS];
|
||||
uECC_word_t t5[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
if (uECC_vli_isZero(Z1, num_words)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */
|
||||
uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
|
||||
uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */
|
||||
uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
|
||||
uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */
|
||||
|
||||
uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */
|
||||
uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */
|
||||
uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */
|
||||
uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */
|
||||
|
||||
uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */
|
||||
uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */
|
||||
if (uECC_vli_testBit(X1, 0)) {
|
||||
uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words);
|
||||
uECC_vli_rshift1(X1, num_words);
|
||||
X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
|
||||
} else {
|
||||
uECC_vli_rshift1(X1, num_words);
|
||||
}
|
||||
|
||||
/* t1 = 3/2*(x1^2 - z1^4) = B */
|
||||
uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */
|
||||
uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */
|
||||
uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */
|
||||
uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */
|
||||
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */
|
||||
/* t4 = B * (A - x3) - y1^4 = y3: */
|
||||
uECC_vli_modSub(t4, X1, t4, curve->p, num_words);
|
||||
|
||||
uECC_vli_set(X1, Z1, num_words);
|
||||
uECC_vli_set(Z1, Y1, num_words);
|
||||
uECC_vli_set(Y1, t4, num_words);
|
||||
}
|
||||
|
||||
void x_side_default(uECC_word_t *result,
|
||||
const uECC_word_t *x,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */
|
||||
uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */
|
||||
uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */
|
||||
/* r = x^3 - 3x + b: */
|
||||
uECC_vli_modAdd(result, result, curve->b, curve->p, num_words);
|
||||
}
|
||||
|
||||
uECC_Curve uECC_secp256r1(void)
|
||||
{
|
||||
return &curve_secp256r1;
|
||||
}
|
||||
|
||||
void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
|
||||
{
|
||||
unsigned int tmp[NUM_ECC_WORDS];
|
||||
int carry;
|
||||
|
||||
/* t */
|
||||
uECC_vli_set(result, product, NUM_ECC_WORDS);
|
||||
|
||||
/* s1 */
|
||||
tmp[0] = tmp[1] = tmp[2] = 0;
|
||||
tmp[3] = product[11];
|
||||
tmp[4] = product[12];
|
||||
tmp[5] = product[13];
|
||||
tmp[6] = product[14];
|
||||
tmp[7] = product[15];
|
||||
carry = uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
|
||||
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* s2 */
|
||||
tmp[3] = product[12];
|
||||
tmp[4] = product[13];
|
||||
tmp[5] = product[14];
|
||||
tmp[6] = product[15];
|
||||
tmp[7] = 0;
|
||||
carry += uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
|
||||
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* s3 */
|
||||
tmp[0] = product[8];
|
||||
tmp[1] = product[9];
|
||||
tmp[2] = product[10];
|
||||
tmp[3] = tmp[4] = tmp[5] = 0;
|
||||
tmp[6] = product[14];
|
||||
tmp[7] = product[15];
|
||||
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* s4 */
|
||||
tmp[0] = product[9];
|
||||
tmp[1] = product[10];
|
||||
tmp[2] = product[11];
|
||||
tmp[3] = product[13];
|
||||
tmp[4] = product[14];
|
||||
tmp[5] = product[15];
|
||||
tmp[6] = product[13];
|
||||
tmp[7] = product[8];
|
||||
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* d1 */
|
||||
tmp[0] = product[11];
|
||||
tmp[1] = product[12];
|
||||
tmp[2] = product[13];
|
||||
tmp[3] = tmp[4] = tmp[5] = 0;
|
||||
tmp[6] = product[8];
|
||||
tmp[7] = product[10];
|
||||
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* d2 */
|
||||
tmp[0] = product[12];
|
||||
tmp[1] = product[13];
|
||||
tmp[2] = product[14];
|
||||
tmp[3] = product[15];
|
||||
tmp[4] = tmp[5] = 0;
|
||||
tmp[6] = product[9];
|
||||
tmp[7] = product[11];
|
||||
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* d3 */
|
||||
tmp[0] = product[13];
|
||||
tmp[1] = product[14];
|
||||
tmp[2] = product[15];
|
||||
tmp[3] = product[8];
|
||||
tmp[4] = product[9];
|
||||
tmp[5] = product[10];
|
||||
tmp[6] = 0;
|
||||
tmp[7] = product[12];
|
||||
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
/* d4 */
|
||||
tmp[0] = product[14];
|
||||
tmp[1] = product[15];
|
||||
tmp[2] = 0;
|
||||
tmp[3] = product[9];
|
||||
tmp[4] = product[10];
|
||||
tmp[5] = product[11];
|
||||
tmp[6] = 0;
|
||||
tmp[7] = product[13];
|
||||
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
|
||||
|
||||
if (carry < 0) {
|
||||
do {
|
||||
carry += uECC_vli_add(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
|
||||
}
|
||||
while (carry < 0);
|
||||
} else {
|
||||
while (carry ||
|
||||
uECC_vli_cmp_unsafe(curve_secp256r1.p, result, NUM_ECC_WORDS) != 1) {
|
||||
carry -= uECC_vli_sub(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve)
|
||||
{
|
||||
return uECC_vli_isZero(point, curve->num_words * 2);
|
||||
}
|
||||
|
||||
void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t t1[NUM_ECC_WORDS];
|
||||
|
||||
uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */
|
||||
uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */
|
||||
uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */
|
||||
uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */
|
||||
}
|
||||
|
||||
/* P = (x1, y1) => 2P, (x2, y2) => P' */
|
||||
static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
|
||||
uECC_word_t * X2, uECC_word_t * Y2,
|
||||
const uECC_word_t * const initial_Z,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t z[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
if (initial_Z) {
|
||||
uECC_vli_set(z, initial_Z, num_words);
|
||||
} else {
|
||||
uECC_vli_clear(z, num_words);
|
||||
z[0] = 1;
|
||||
}
|
||||
|
||||
uECC_vli_set(X2, X1, num_words);
|
||||
uECC_vli_set(Y2, Y1, num_words);
|
||||
|
||||
apply_z(X1, Y1, z, curve);
|
||||
curve->double_jacobian(X1, Y1, z, curve);
|
||||
apply_z(X2, Y2, z, curve);
|
||||
}
|
||||
|
||||
void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
|
||||
uECC_word_t * X2, uECC_word_t * Y2,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
uECC_word_t t5[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
|
||||
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
|
||||
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
|
||||
uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
|
||||
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
|
||||
uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */
|
||||
|
||||
uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */
|
||||
uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */
|
||||
uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */
|
||||
uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */
|
||||
uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */
|
||||
uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */
|
||||
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */
|
||||
|
||||
uECC_vli_set(X2, t5, num_words);
|
||||
}
|
||||
|
||||
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
|
||||
or P => P - Q, Q => P + Q
|
||||
*/
|
||||
static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1,
|
||||
uECC_word_t * X2, uECC_word_t * Y2,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
uECC_word_t t5[NUM_ECC_WORDS];
|
||||
uECC_word_t t6[NUM_ECC_WORDS];
|
||||
uECC_word_t t7[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
|
||||
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
|
||||
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
|
||||
uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
|
||||
uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */
|
||||
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
|
||||
|
||||
uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */
|
||||
uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */
|
||||
uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */
|
||||
uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */
|
||||
uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */
|
||||
|
||||
uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */
|
||||
uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */
|
||||
/* t4 = (y2 - y1)*(B - x3) - E = y3: */
|
||||
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words);
|
||||
|
||||
uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */
|
||||
uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */
|
||||
uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */
|
||||
uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */
|
||||
/* t2 = (y2+y1)*(x3' - B) - E = y3': */
|
||||
uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words);
|
||||
|
||||
uECC_vli_set(X1, t7, num_words);
|
||||
}
|
||||
|
||||
void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
|
||||
const uECC_word_t * scalar,
|
||||
const uECC_word_t * initial_Z,
|
||||
bitcount_t num_bits, uECC_Curve curve)
|
||||
{
|
||||
/* R0 and R1 */
|
||||
uECC_word_t Rx[2][NUM_ECC_WORDS];
|
||||
uECC_word_t Ry[2][NUM_ECC_WORDS];
|
||||
uECC_word_t z[NUM_ECC_WORDS];
|
||||
bitcount_t i;
|
||||
uECC_word_t nb;
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
uECC_vli_set(Rx[1], point, num_words);
|
||||
uECC_vli_set(Ry[1], point + num_words, num_words);
|
||||
|
||||
XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve);
|
||||
|
||||
for (i = num_bits - 2; i > 0; --i) {
|
||||
nb = !uECC_vli_testBit(scalar, i);
|
||||
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
|
||||
XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
|
||||
}
|
||||
|
||||
nb = !uECC_vli_testBit(scalar, 0);
|
||||
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
|
||||
|
||||
/* Find final 1/Z value. */
|
||||
uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */
|
||||
uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */
|
||||
uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */
|
||||
uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0))*/
|
||||
/* yP / (xP * Yb * (X1 - X0)) */
|
||||
uECC_vli_modMult_fast(z, z, point + num_words, curve);
|
||||
/* Xb * yP / (xP * Yb * (X1 - X0)) */
|
||||
uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve);
|
||||
/* End 1/Z calculation */
|
||||
|
||||
XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
|
||||
apply_z(Rx[0], Ry[0], z, curve);
|
||||
|
||||
uECC_vli_set(result, Rx[0], num_words);
|
||||
uECC_vli_set(result + num_words, Ry[0], num_words);
|
||||
}
|
||||
|
||||
uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
|
||||
uECC_word_t *k1, uECC_Curve curve)
|
||||
{
|
||||
|
||||
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||
|
||||
bitcount_t num_n_bits = curve->num_n_bits;
|
||||
|
||||
uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||
|
||||
(num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
|
||||
uECC_vli_testBit(k0, num_n_bits));
|
||||
|
||||
uECC_vli_add(k1, k0, curve->n, num_n_words);
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
|
||||
uECC_word_t *private_key,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t tmp1[NUM_ECC_WORDS];
|
||||
uECC_word_t tmp2[NUM_ECC_WORDS];
|
||||
uECC_word_t *p2[2] = {tmp1, tmp2};
|
||||
uECC_word_t carry;
|
||||
|
||||
/* Regularize the bitcount for the private key so that attackers cannot
|
||||
* use a side channel attack to learn the number of leading zeros. */
|
||||
carry = regularize_k(private_key, tmp1, tmp2, curve);
|
||||
|
||||
EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);
|
||||
|
||||
if (EccPoint_isZero(result, curve)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Converts an integer in uECC native format to big-endian bytes. */
|
||||
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
|
||||
const unsigned int *native)
|
||||
{
|
||||
wordcount_t i;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
unsigned b = num_bytes - 1 - i;
|
||||
bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts big-endian bytes to an integer in uECC native format. */
|
||||
void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
|
||||
int num_bytes)
|
||||
{
|
||||
wordcount_t i;
|
||||
uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
unsigned b = num_bytes - 1 - i;
|
||||
native[b / uECC_WORD_SIZE] |=
|
||||
(uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
|
||||
wordcount_t num_words)
|
||||
{
|
||||
uECC_word_t mask = (uECC_word_t)-1;
|
||||
uECC_word_t tries;
|
||||
bitcount_t num_bits = uECC_vli_numBits(top, num_words);
|
||||
|
||||
if (!g_rng_function) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
|
||||
if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
random[num_words - 1] &=
|
||||
mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
|
||||
if (!uECC_vli_isZero(random, num_words) &&
|
||||
uECC_vli_cmp(top, random, num_words) == 1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t tmp1[NUM_ECC_WORDS];
|
||||
uECC_word_t tmp2[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
|
||||
/* The point at infinity is invalid. */
|
||||
if (EccPoint_isZero(point, curve)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* x and y must be smaller than p. */
|
||||
if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||
|
||||
uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
uECC_vli_modSquare_fast(tmp1, point + num_words, curve);
|
||||
curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */
|
||||
|
||||
/* Make sure that y^2 == x^3 + ax + b */
|
||||
if (uECC_vli_equal(tmp1, tmp2, num_words) != 0)
|
||||
return -3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
|
||||
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(
|
||||
_public + curve->num_words,
|
||||
public_key + curve->num_bytes,
|
||||
curve->num_bytes);
|
||||
|
||||
if (uECC_vli_cmp_unsafe(_public, curve->G, NUM_ECC_WORDS * 2) == 0) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
return uECC_valid_point(_public, curve);
|
||||
}
|
||||
|
||||
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t _private[NUM_ECC_WORDS];
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
|
||||
uECC_vli_bytesToNative(
|
||||
_private,
|
||||
private_key,
|
||||
BITS_TO_BYTES(curve->num_n_bits));
|
||||
|
||||
/* Make sure the private key is in the range [1, n-1]. */
|
||||
if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute public key. */
|
||||
if (!EccPoint_compute_public_key(_public, _private, curve)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public);
|
||||
uECC_vli_nativeToBytes(
|
||||
public_key +
|
||||
curve->num_bytes, curve->num_bytes, _public + curve->num_words);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
200
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dh.c
Normal file
200
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dh.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/* ec_dh.c - TinyCrypt implementation of EC-DH */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/ecc.h"
|
||||
#include "../include/tinycrypt/ecc_dh.h"
|
||||
#include <string.h>
|
||||
|
||||
#if default_RNG_defined
|
||||
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
|
||||
#else
|
||||
static uECC_RNG_Function g_rng_function = 0;
|
||||
#endif
|
||||
|
||||
int uECC_make_key_with_d(uint8_t *public_key, uint8_t *private_key,
|
||||
unsigned int *d, uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t _private[NUM_ECC_WORDS];
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
|
||||
/* This function is designed for test purposes-only (such as validating NIST
|
||||
* test vectors) as it uses a provided value for d instead of generating
|
||||
* it uniformly at random. */
|
||||
memcpy (_private, d, NUM_ECC_BYTES);
|
||||
|
||||
/* Computing public-key from private: */
|
||||
if (EccPoint_compute_public_key(_public, _private, curve)) {
|
||||
|
||||
/* Converting buffers to correct bit order: */
|
||||
uECC_vli_nativeToBytes(private_key,
|
||||
BITS_TO_BYTES(curve->num_n_bits),
|
||||
_private);
|
||||
uECC_vli_nativeToBytes(public_key,
|
||||
curve->num_bytes,
|
||||
_public);
|
||||
uECC_vli_nativeToBytes(public_key + curve->num_bytes,
|
||||
curve->num_bytes,
|
||||
_public + curve->num_words);
|
||||
|
||||
/* erasing temporary buffer used to store secret: */
|
||||
memset(_private, 0, NUM_ECC_BYTES);
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t _random[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t _private[NUM_ECC_WORDS];
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t tries;
|
||||
|
||||
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
|
||||
/* Generating _private uniformly at random: */
|
||||
uECC_RNG_Function rng_function = uECC_get_rng();
|
||||
if (!rng_function ||
|
||||
!rng_function((uint8_t *)_random, 2 * NUM_ECC_WORDS*uECC_WORD_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* computing modular reduction of _random (see FIPS 186.4 B.4.1): */
|
||||
uECC_vli_mmod(_private, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits));
|
||||
|
||||
/* Computing public-key from private: */
|
||||
if (EccPoint_compute_public_key(_public, _private, curve)) {
|
||||
|
||||
/* Converting buffers to correct bit order: */
|
||||
uECC_vli_nativeToBytes(private_key,
|
||||
BITS_TO_BYTES(curve->num_n_bits),
|
||||
_private);
|
||||
uECC_vli_nativeToBytes(public_key,
|
||||
curve->num_bytes,
|
||||
_public);
|
||||
uECC_vli_nativeToBytes(public_key + curve->num_bytes,
|
||||
curve->num_bytes,
|
||||
_public + curve->num_words);
|
||||
|
||||
/* erasing temporary buffer that stored secret: */
|
||||
memset(_private, 0, NUM_ECC_BYTES);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
|
||||
uint8_t *secret, uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t _private[NUM_ECC_WORDS];
|
||||
|
||||
uECC_word_t tmp[NUM_ECC_WORDS];
|
||||
uECC_word_t *p2[2] = {_private, tmp};
|
||||
uECC_word_t *initial_Z = 0;
|
||||
uECC_word_t carry;
|
||||
wordcount_t num_words = curve->num_words;
|
||||
wordcount_t num_bytes = curve->num_bytes;
|
||||
int r;
|
||||
|
||||
/* Converting buffers to correct bit order: */
|
||||
uECC_vli_bytesToNative(_private,
|
||||
private_key,
|
||||
BITS_TO_BYTES(curve->num_n_bits));
|
||||
uECC_vli_bytesToNative(_public,
|
||||
public_key,
|
||||
num_bytes);
|
||||
uECC_vli_bytesToNative(_public + num_words,
|
||||
public_key + num_bytes,
|
||||
num_bytes);
|
||||
|
||||
/* Regularize the bitcount for the private key so that attackers cannot use a
|
||||
* side channel attack to learn the number of leading zeros. */
|
||||
carry = regularize_k(_private, _private, tmp, curve);
|
||||
|
||||
/* If an RNG function was specified, try to get a random initial Z value to
|
||||
* improve protection against side-channel attacks. */
|
||||
if (g_rng_function) {
|
||||
if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) {
|
||||
r = 0;
|
||||
goto clear_and_out;
|
||||
}
|
||||
initial_Z = p2[carry];
|
||||
}
|
||||
|
||||
EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1,
|
||||
curve);
|
||||
|
||||
uECC_vli_nativeToBytes(secret, num_bytes, _public);
|
||||
r = !EccPoint_isZero(_public, curve);
|
||||
|
||||
clear_and_out:
|
||||
/* erasing temporary buffer used to store secret: */
|
||||
memset(p2, 0, sizeof(p2));
|
||||
__asm__ __volatile__("" :: "g"(p2) : "memory");
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
__asm__ __volatile__("" :: "g"(tmp) : "memory");
|
||||
memset(_private, 0, sizeof(_private));
|
||||
__asm__ __volatile__("" :: "g"(_private) : "memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
295
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dsa.c
Normal file
295
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/ecc_dsa.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/* ec_dsa.c - TinyCrypt implementation of EC-DSA */
|
||||
|
||||
/* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/ecc.h"
|
||||
#include "../include/tinycrypt/ecc_dsa.h"
|
||||
|
||||
#if default_RNG_defined
|
||||
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
|
||||
#else
|
||||
static uECC_RNG_Function g_rng_function = 0;
|
||||
#endif
|
||||
|
||||
static void bits2int(uECC_word_t *native, const uint8_t *bits,
|
||||
unsigned bits_size, uECC_Curve curve)
|
||||
{
|
||||
unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);
|
||||
unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||
int shift;
|
||||
uECC_word_t carry;
|
||||
uECC_word_t *ptr;
|
||||
|
||||
if (bits_size > num_n_bytes) {
|
||||
bits_size = num_n_bytes;
|
||||
}
|
||||
|
||||
uECC_vli_clear(native, num_n_words);
|
||||
uECC_vli_bytesToNative(native, bits, bits_size);
|
||||
if (bits_size * 8 <= (unsigned)curve->num_n_bits) {
|
||||
return;
|
||||
}
|
||||
shift = bits_size * 8 - curve->num_n_bits;
|
||||
carry = 0;
|
||||
ptr = native + num_n_words;
|
||||
while (ptr-- > native) {
|
||||
uECC_word_t temp = *ptr;
|
||||
*ptr = (temp >> shift) | carry;
|
||||
carry = temp << (uECC_WORD_BITS - shift);
|
||||
}
|
||||
|
||||
/* Reduce mod curve_n */
|
||||
if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {
|
||||
uECC_vli_sub(native, native, curve->n, num_n_words);
|
||||
}
|
||||
}
|
||||
|
||||
int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, uECC_word_t *k, uint8_t *signature,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t tmp[NUM_ECC_WORDS];
|
||||
uECC_word_t s[NUM_ECC_WORDS];
|
||||
uECC_word_t *k2[2] = {tmp, s};
|
||||
uECC_word_t p[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t carry;
|
||||
wordcount_t num_words = curve->num_words;
|
||||
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||
bitcount_t num_n_bits = curve->num_n_bits;
|
||||
|
||||
/* Make sure 0 < k < curve_n */
|
||||
if (uECC_vli_isZero(k, num_words) ||
|
||||
uECC_vli_cmp(curve->n, k, num_n_words) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
carry = regularize_k(k, tmp, s, curve);
|
||||
EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve);
|
||||
if (uECC_vli_isZero(p, num_words)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If an RNG function was specified, get a random number
|
||||
to prevent side channel analysis of k. */
|
||||
if (!g_rng_function) {
|
||||
uECC_vli_clear(tmp, num_n_words);
|
||||
tmp[0] = 1;
|
||||
}
|
||||
else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prevent side channel analysis of uECC_vli_modInv() to determine
|
||||
bits of k / the private key by premultiplying by a random number */
|
||||
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
|
||||
uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */
|
||||
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */
|
||||
|
||||
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
|
||||
|
||||
/* tmp = d: */
|
||||
uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits));
|
||||
|
||||
s[num_n_words - 1] = 0;
|
||||
uECC_vli_set(s, p, num_words);
|
||||
uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */
|
||||
|
||||
bits2int(tmp, message_hash, hash_size, curve);
|
||||
uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */
|
||||
uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */
|
||||
if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, uint8_t *signature, uECC_Curve curve)
|
||||
{
|
||||
uECC_word_t _random[2*NUM_ECC_WORDS];
|
||||
uECC_word_t k[NUM_ECC_WORDS];
|
||||
uECC_word_t tries;
|
||||
|
||||
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
|
||||
/* Generating _random uniformly at random: */
|
||||
uECC_RNG_Function rng_function = uECC_get_rng();
|
||||
if (!rng_function ||
|
||||
!rng_function((uint8_t *)_random, 2*NUM_ECC_WORDS*uECC_WORD_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// computing k as modular reduction of _random (see FIPS 186.4 B.5.1):
|
||||
uECC_vli_mmod(k, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits));
|
||||
|
||||
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature,
|
||||
curve)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bitcount_t smax(bitcount_t a, bitcount_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, const uint8_t *signature,
|
||||
uECC_Curve curve)
|
||||
{
|
||||
|
||||
uECC_word_t u1[NUM_ECC_WORDS], u2[NUM_ECC_WORDS];
|
||||
uECC_word_t z[NUM_ECC_WORDS];
|
||||
uECC_word_t sum[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t rx[NUM_ECC_WORDS];
|
||||
uECC_word_t ry[NUM_ECC_WORDS];
|
||||
uECC_word_t tx[NUM_ECC_WORDS];
|
||||
uECC_word_t ty[NUM_ECC_WORDS];
|
||||
uECC_word_t tz[NUM_ECC_WORDS];
|
||||
const uECC_word_t *points[4];
|
||||
const uECC_word_t *point;
|
||||
bitcount_t num_bits;
|
||||
bitcount_t i;
|
||||
|
||||
uECC_word_t _public[NUM_ECC_WORDS * 2];
|
||||
uECC_word_t r[NUM_ECC_WORDS], s[NUM_ECC_WORDS];
|
||||
wordcount_t num_words = curve->num_words;
|
||||
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||
|
||||
rx[num_n_words - 1] = 0;
|
||||
r[num_n_words - 1] = 0;
|
||||
s[num_n_words - 1] = 0;
|
||||
|
||||
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes,
|
||||
curve->num_bytes);
|
||||
uECC_vli_bytesToNative(r, signature, curve->num_bytes);
|
||||
uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
|
||||
|
||||
/* r, s must not be 0. */
|
||||
if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* r, s must be < n. */
|
||||
if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 ||
|
||||
uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate u1 and u2. */
|
||||
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
|
||||
u1[num_n_words - 1] = 0;
|
||||
bits2int(u1, message_hash, hash_size, curve);
|
||||
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
|
||||
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
|
||||
|
||||
/* Calculate sum = G + Q. */
|
||||
uECC_vli_set(sum, _public, num_words);
|
||||
uECC_vli_set(sum + num_words, _public + num_words, num_words);
|
||||
uECC_vli_set(tx, curve->G, num_words);
|
||||
uECC_vli_set(ty, curve->G + num_words, num_words);
|
||||
uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
|
||||
XYcZ_add(tx, ty, sum, sum + num_words, curve);
|
||||
uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
|
||||
apply_z(sum, sum + num_words, z, curve);
|
||||
|
||||
/* Use Shamir's trick to calculate u1*G + u2*Q */
|
||||
points[0] = 0;
|
||||
points[1] = curve->G;
|
||||
points[2] = _public;
|
||||
points[3] = sum;
|
||||
num_bits = smax(uECC_vli_numBits(u1, num_n_words),
|
||||
uECC_vli_numBits(u2, num_n_words));
|
||||
|
||||
point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
|
||||
((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
|
||||
uECC_vli_set(rx, point, num_words);
|
||||
uECC_vli_set(ry, point + num_words, num_words);
|
||||
uECC_vli_clear(z, num_words);
|
||||
z[0] = 1;
|
||||
|
||||
for (i = num_bits - 2; i >= 0; --i) {
|
||||
uECC_word_t index;
|
||||
curve->double_jacobian(rx, ry, z, curve);
|
||||
|
||||
index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
|
||||
point = points[index];
|
||||
if (point) {
|
||||
uECC_vli_set(tx, point, num_words);
|
||||
uECC_vli_set(ty, point + num_words, num_words);
|
||||
apply_z(tx, ty, z, curve);
|
||||
uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
|
||||
XYcZ_add(tx, ty, rx, ry, curve);
|
||||
uECC_vli_modMult_fast(z, z, tz, curve);
|
||||
}
|
||||
}
|
||||
|
||||
uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
|
||||
apply_z(rx, ry, z, curve);
|
||||
|
||||
/* v = x1 (mod n) */
|
||||
if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) {
|
||||
uECC_vli_sub(rx, rx, curve->n, num_n_words);
|
||||
}
|
||||
|
||||
/* Accept only if v == r. */
|
||||
return (int)(uECC_vli_equal(rx, r, num_words) == 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/* uECC_platform_specific.c - Implementation of platform specific functions*/
|
||||
|
||||
/* Copyright (c) 2014, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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.
|
||||
*
|
||||
* uECC_platform_specific.c -- Implementation of platform specific functions
|
||||
*/
|
||||
|
||||
|
||||
#if defined(unix) || defined(__linux__) || defined(__unix__) || \
|
||||
defined(__unix) | (defined(__APPLE__) && defined(__MACH__)) || \
|
||||
defined(uECC_POSIX)
|
||||
|
||||
/* Some POSIX-like system with /dev/urandom or /dev/random. */
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
int default_CSPRNG(uint8_t *dest, unsigned int size) {
|
||||
|
||||
/* input sanity check: */
|
||||
if (dest == (uint8_t *) 0 || (size <= 0))
|
||||
return 0;
|
||||
|
||||
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char *ptr = (char *)dest;
|
||||
size_t left = (size_t) size;
|
||||
while (left > 0) {
|
||||
ssize_t bytes_read = read(fd, ptr, left);
|
||||
if (bytes_read <= 0) { // read failed
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
left -= bytes_read;
|
||||
ptr += bytes_read;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* platform */
|
||||
|
||||
148
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac.c
Normal file
148
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/* hmac.c - TinyCrypt implementation of the HMAC algorithm */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/hmac.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
static void rekey(uint8_t *key, const uint8_t *new_key, unsigned int key_size)
|
||||
{
|
||||
const uint8_t inner_pad = (uint8_t) 0x36;
|
||||
const uint8_t outer_pad = (uint8_t) 0x5c;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < key_size; ++i) {
|
||||
key[i] = inner_pad ^ new_key[i];
|
||||
key[i + TC_SHA256_BLOCK_SIZE] = outer_pad ^ new_key[i];
|
||||
}
|
||||
for (; i < TC_SHA256_BLOCK_SIZE; ++i) {
|
||||
key[i] = inner_pad; key[i + TC_SHA256_BLOCK_SIZE] = outer_pad;
|
||||
}
|
||||
}
|
||||
|
||||
int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key,
|
||||
unsigned int key_size)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (ctx == (TCHmacState_t) 0 ||
|
||||
key == (const uint8_t *) 0 ||
|
||||
key_size == 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
const uint8_t dummy_key[key_size];
|
||||
struct tc_hmac_state_struct dummy_state;
|
||||
|
||||
if (key_size <= TC_SHA256_BLOCK_SIZE) {
|
||||
/*
|
||||
* The next three lines consist of dummy calls just to avoid
|
||||
* certain timing attacks. Without these dummy calls,
|
||||
* adversaries would be able to learn whether the key_size is
|
||||
* greater than TC_SHA256_BLOCK_SIZE by measuring the time
|
||||
* consumed in this process.
|
||||
*/
|
||||
(void)tc_sha256_init(&dummy_state.hash_state);
|
||||
(void)tc_sha256_update(&dummy_state.hash_state,
|
||||
dummy_key,
|
||||
key_size);
|
||||
(void)tc_sha256_final(&dummy_state.key[TC_SHA256_DIGEST_SIZE],
|
||||
&dummy_state.hash_state);
|
||||
|
||||
/* Actual code for when key_size <= TC_SHA256_BLOCK_SIZE: */
|
||||
rekey(ctx->key, key, key_size);
|
||||
} else {
|
||||
(void)tc_sha256_init(&ctx->hash_state);
|
||||
(void)tc_sha256_update(&ctx->hash_state, key, key_size);
|
||||
(void)tc_sha256_final(&ctx->key[TC_SHA256_DIGEST_SIZE],
|
||||
&ctx->hash_state);
|
||||
rekey(ctx->key,
|
||||
&ctx->key[TC_SHA256_DIGEST_SIZE],
|
||||
TC_SHA256_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_hmac_init(TCHmacState_t ctx)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (ctx == (TCHmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
(void) tc_sha256_init(&ctx->hash_state);
|
||||
(void) tc_sha256_update(&ctx->hash_state, ctx->key, TC_SHA256_BLOCK_SIZE);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_hmac_update(TCHmacState_t ctx,
|
||||
const void *data,
|
||||
unsigned int data_length)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (ctx == (TCHmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
(void)tc_sha256_update(&ctx->hash_state, data, data_length);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (tag == (uint8_t *) 0 ||
|
||||
taglen != TC_SHA256_DIGEST_SIZE ||
|
||||
ctx == (TCHmacState_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
(void) tc_sha256_final(tag, &ctx->hash_state);
|
||||
|
||||
(void)tc_sha256_init(&ctx->hash_state);
|
||||
(void)tc_sha256_update(&ctx->hash_state,
|
||||
&ctx->key[TC_SHA256_BLOCK_SIZE],
|
||||
TC_SHA256_BLOCK_SIZE);
|
||||
(void)tc_sha256_update(&ctx->hash_state, tag, TC_SHA256_DIGEST_SIZE);
|
||||
(void)tc_sha256_final(tag, &ctx->hash_state);
|
||||
|
||||
/* destroy the current state */
|
||||
_set(ctx, 0, sizeof(*ctx));
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
212
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac_prng.c
Normal file
212
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/hmac_prng.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/* hmac_prng.c - TinyCrypt implementation of HMAC-PRNG */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/hmac_prng.h"
|
||||
#include "../include/tinycrypt/hmac.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
/*
|
||||
* min bytes in the seed string.
|
||||
* MIN_SLEN*8 must be at least the expected security level.
|
||||
*/
|
||||
static const unsigned int MIN_SLEN = 32;
|
||||
|
||||
/*
|
||||
* max bytes in the seed string;
|
||||
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
|
||||
*/
|
||||
static const unsigned int MAX_SLEN = UINT32_MAX;
|
||||
|
||||
/*
|
||||
* max bytes in the personalization string;
|
||||
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
|
||||
*/
|
||||
static const unsigned int MAX_PLEN = UINT32_MAX;
|
||||
|
||||
/*
|
||||
* max bytes in the additional_info string;
|
||||
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
|
||||
*/
|
||||
static const unsigned int MAX_ALEN = UINT32_MAX;
|
||||
|
||||
/*
|
||||
* max number of generates between re-seeds;
|
||||
* TinyCrypt accepts up to (2^32 - 1) which is the maximal value of
|
||||
* a 32-bit unsigned int variable, while SP800-90A specifies a maximum of 2^48.
|
||||
*/
|
||||
static const unsigned int MAX_GENS = UINT32_MAX;
|
||||
|
||||
/*
|
||||
* maximum bytes per generate call;
|
||||
* SP800-90A specifies a maximum up to 2^19.
|
||||
*/
|
||||
static const unsigned int MAX_OUT = (1 << 19);
|
||||
|
||||
/*
|
||||
* Assumes: prng != NULL, e != NULL, len >= 0.
|
||||
*/
|
||||
static void update(TCHmacPrng_t prng, const uint8_t *e, unsigned int len)
|
||||
{
|
||||
const uint8_t separator0 = 0x00;
|
||||
const uint8_t separator1 = 0x01;
|
||||
|
||||
/* use current state, e and separator 0 to compute a new prng key: */
|
||||
(void)tc_hmac_init(&prng->h);
|
||||
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
|
||||
(void)tc_hmac_update(&prng->h, &separator0, sizeof(separator0));
|
||||
(void)tc_hmac_update(&prng->h, e, len);
|
||||
(void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h);
|
||||
/* configure the new prng key into the prng's instance of hmac */
|
||||
(void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
|
||||
/* use the new key to compute a new state variable v */
|
||||
(void)tc_hmac_init(&prng->h);
|
||||
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
|
||||
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
|
||||
|
||||
/* use current state, e and separator 1 to compute a new prng key: */
|
||||
(void)tc_hmac_init(&prng->h);
|
||||
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
|
||||
(void)tc_hmac_update(&prng->h, &separator1, sizeof(separator1));
|
||||
(void)tc_hmac_update(&prng->h, e, len);
|
||||
(void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h);
|
||||
/* configure the new prng key into the prng's instance of hmac */
|
||||
(void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
|
||||
/* use the new key to compute a new state variable v */
|
||||
(void)tc_hmac_init(&prng->h);
|
||||
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
|
||||
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
|
||||
}
|
||||
|
||||
int tc_hmac_prng_init(TCHmacPrng_t prng,
|
||||
const uint8_t *personalization,
|
||||
unsigned int plen)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (prng == (TCHmacPrng_t) 0 ||
|
||||
personalization == (uint8_t *) 0 ||
|
||||
plen > MAX_PLEN) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/* put the generator into a known state: */
|
||||
_set(prng->key, 0x00, sizeof(prng->key));
|
||||
_set(prng->v, 0x01, sizeof(prng->v));
|
||||
tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
/* update assumes SOME key has been configured into HMAC */
|
||||
|
||||
update(prng, personalization, plen);
|
||||
|
||||
/* force a reseed before allowing tc_hmac_prng_generate to succeed: */
|
||||
prng->countdown = 0;
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_hmac_prng_reseed(TCHmacPrng_t prng,
|
||||
const uint8_t *seed,
|
||||
unsigned int seedlen,
|
||||
const uint8_t *additional_input,
|
||||
unsigned int additionallen)
|
||||
{
|
||||
|
||||
/* input sanity check: */
|
||||
if (prng == (TCHmacPrng_t) 0 ||
|
||||
seed == (const uint8_t *) 0 ||
|
||||
seedlen < MIN_SLEN ||
|
||||
seedlen > MAX_SLEN) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
if (additional_input != (const uint8_t *) 0) {
|
||||
/*
|
||||
* Abort if additional_input is provided but has inappropriate
|
||||
* length
|
||||
*/
|
||||
if (additionallen == 0 ||
|
||||
additionallen > MAX_ALEN) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else {
|
||||
/* call update for the seed and additional_input */
|
||||
update(prng, seed, seedlen);
|
||||
update(prng, additional_input, additionallen);
|
||||
}
|
||||
} else {
|
||||
/* call update only for the seed */
|
||||
update(prng, seed, seedlen);
|
||||
}
|
||||
|
||||
/* ... and enable hmac_prng_generate */
|
||||
prng->countdown = MAX_GENS;
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng)
|
||||
{
|
||||
unsigned int bufferlen;
|
||||
|
||||
/* input sanity check: */
|
||||
if (out == (uint8_t *) 0 ||
|
||||
prng == (TCHmacPrng_t) 0 ||
|
||||
outlen == 0 ||
|
||||
outlen > MAX_OUT) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (prng->countdown == 0) {
|
||||
return TC_HMAC_PRNG_RESEED_REQ;
|
||||
}
|
||||
|
||||
prng->countdown--;
|
||||
|
||||
while (outlen != 0) {
|
||||
/* operate HMAC in OFB mode to create "random" outputs */
|
||||
(void)tc_hmac_init(&prng->h);
|
||||
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
|
||||
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
|
||||
|
||||
bufferlen = (TC_SHA256_DIGEST_SIZE > outlen) ?
|
||||
outlen : TC_SHA256_DIGEST_SIZE;
|
||||
(void)_copy(out, bufferlen, prng->v, bufferlen);
|
||||
|
||||
out += bufferlen;
|
||||
outlen = (outlen > TC_SHA256_DIGEST_SIZE) ?
|
||||
(outlen - TC_SHA256_DIGEST_SIZE) : 0;
|
||||
}
|
||||
|
||||
/* block future PRNG compromises from revealing past state */
|
||||
update(prng, prng->v, TC_SHA256_DIGEST_SIZE);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
217
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/sha256.c
Normal file
217
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/sha256.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/* sha256.c - TinyCrypt SHA-256 crypto hash algorithm implementation */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/sha256.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
#include "../include/tinycrypt/utils.h"
|
||||
|
||||
static void compress(unsigned int *iv, const uint8_t *data);
|
||||
|
||||
int tc_sha256_init(TCSha256State_t s)
|
||||
{
|
||||
/* input sanity check: */
|
||||
if (s == (TCSha256State_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setting the initial state values.
|
||||
* These values correspond to the first 32 bits of the fractional parts
|
||||
* of the square roots of the first 8 primes: 2, 3, 5, 7, 11, 13, 17
|
||||
* and 19.
|
||||
*/
|
||||
_set((uint8_t *) s, 0x00, sizeof(*s));
|
||||
s->iv[0] = 0x6a09e667;
|
||||
s->iv[1] = 0xbb67ae85;
|
||||
s->iv[2] = 0x3c6ef372;
|
||||
s->iv[3] = 0xa54ff53a;
|
||||
s->iv[4] = 0x510e527f;
|
||||
s->iv[5] = 0x9b05688c;
|
||||
s->iv[6] = 0x1f83d9ab;
|
||||
s->iv[7] = 0x5be0cd19;
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_sha256_update(TCSha256State_t s, const uint8_t *data, size_t datalen)
|
||||
{
|
||||
/* input sanity check: */
|
||||
if (s == (TCSha256State_t) 0 ||
|
||||
data == (void *) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
} else if (datalen == 0) {
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
while (datalen-- > 0) {
|
||||
s->leftover[s->leftover_offset++] = *(data++);
|
||||
if (s->leftover_offset >= TC_SHA256_BLOCK_SIZE) {
|
||||
compress(s->iv, s->leftover);
|
||||
s->leftover_offset = 0;
|
||||
s->bits_hashed += (TC_SHA256_BLOCK_SIZE << 3);
|
||||
}
|
||||
}
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
int tc_sha256_final(uint8_t *digest, TCSha256State_t s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* input sanity check: */
|
||||
if (digest == (uint8_t *) 0 ||
|
||||
s == (TCSha256State_t) 0) {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
s->bits_hashed += (s->leftover_offset << 3);
|
||||
|
||||
s->leftover[s->leftover_offset++] = 0x80; /* always room for one byte */
|
||||
if (s->leftover_offset > (sizeof(s->leftover) - 8)) {
|
||||
/* there is not room for all the padding in this block */
|
||||
_set(s->leftover + s->leftover_offset, 0x00,
|
||||
sizeof(s->leftover) - s->leftover_offset);
|
||||
compress(s->iv, s->leftover);
|
||||
s->leftover_offset = 0;
|
||||
}
|
||||
|
||||
/* add the padding and the length in big-Endian format */
|
||||
_set(s->leftover + s->leftover_offset, 0x00,
|
||||
sizeof(s->leftover) - 8 - s->leftover_offset);
|
||||
s->leftover[sizeof(s->leftover) - 1] = (uint8_t)(s->bits_hashed);
|
||||
s->leftover[sizeof(s->leftover) - 2] = (uint8_t)(s->bits_hashed >> 8);
|
||||
s->leftover[sizeof(s->leftover) - 3] = (uint8_t)(s->bits_hashed >> 16);
|
||||
s->leftover[sizeof(s->leftover) - 4] = (uint8_t)(s->bits_hashed >> 24);
|
||||
s->leftover[sizeof(s->leftover) - 5] = (uint8_t)(s->bits_hashed >> 32);
|
||||
s->leftover[sizeof(s->leftover) - 6] = (uint8_t)(s->bits_hashed >> 40);
|
||||
s->leftover[sizeof(s->leftover) - 7] = (uint8_t)(s->bits_hashed >> 48);
|
||||
s->leftover[sizeof(s->leftover) - 8] = (uint8_t)(s->bits_hashed >> 56);
|
||||
|
||||
/* hash the padding and length */
|
||||
compress(s->iv, s->leftover);
|
||||
|
||||
/* copy the iv out to digest */
|
||||
for (i = 0; i < TC_SHA256_STATE_BLOCKS; ++i) {
|
||||
unsigned int t = *((unsigned int *) &s->iv[i]);
|
||||
*digest++ = (uint8_t)(t >> 24);
|
||||
*digest++ = (uint8_t)(t >> 16);
|
||||
*digest++ = (uint8_t)(t >> 8);
|
||||
*digest++ = (uint8_t)(t);
|
||||
}
|
||||
|
||||
/* destroy the current state */
|
||||
_set(s, 0, sizeof(*s));
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializing SHA-256 Hash constant words K.
|
||||
* These values correspond to the first 32 bits of the fractional parts of the
|
||||
* cube roots of the first 64 primes between 2 and 311.
|
||||
*/
|
||||
static const unsigned int k256[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
static inline unsigned int ROTR(unsigned int a, unsigned int n)
|
||||
{
|
||||
return (((a) >> n) | ((a) << (32 - n)));
|
||||
}
|
||||
|
||||
#define Sigma0(a)(ROTR((a), 2) ^ ROTR((a), 13) ^ ROTR((a), 22))
|
||||
#define Sigma1(a)(ROTR((a), 6) ^ ROTR((a), 11) ^ ROTR((a), 25))
|
||||
#define sigma0(a)(ROTR((a), 7) ^ ROTR((a), 18) ^ ((a) >> 3))
|
||||
#define sigma1(a)(ROTR((a), 17) ^ ROTR((a), 19) ^ ((a) >> 10))
|
||||
|
||||
#define Ch(a, b, c)(((a) & (b)) ^ ((~(a)) & (c)))
|
||||
#define Maj(a, b, c)(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)))
|
||||
|
||||
static inline unsigned int BigEndian(const uint8_t **c)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
|
||||
n = (((unsigned int)(*((*c)++))) << 24);
|
||||
n |= ((unsigned int)(*((*c)++)) << 16);
|
||||
n |= ((unsigned int)(*((*c)++)) << 8);
|
||||
n |= ((unsigned int)(*((*c)++)));
|
||||
return n;
|
||||
}
|
||||
|
||||
static void compress(unsigned int *iv, const uint8_t *data)
|
||||
{
|
||||
unsigned int a, b, c, d, e, f, g, h;
|
||||
unsigned int s0, s1;
|
||||
unsigned int t1, t2;
|
||||
unsigned int work_space[16];
|
||||
unsigned int n;
|
||||
unsigned int i;
|
||||
|
||||
a = iv[0]; b = iv[1]; c = iv[2]; d = iv[3];
|
||||
e = iv[4]; f = iv[5]; g = iv[6]; h = iv[7];
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
n = BigEndian(&data);
|
||||
t1 = work_space[i] = n;
|
||||
t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i];
|
||||
t2 = Sigma0(a) + Maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
|
||||
for ( ; i < 64; ++i) {
|
||||
s0 = work_space[(i+1)&0x0f];
|
||||
s0 = sigma0(s0);
|
||||
s1 = work_space[(i+14)&0x0f];
|
||||
s1 = sigma1(s1);
|
||||
|
||||
t1 = work_space[i&0xf] += s0 + s1 + work_space[(i+9)&0xf];
|
||||
t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i];
|
||||
t2 = Sigma0(a) + Maj(a, b, c);
|
||||
h = g; g = f; f = e; e = d + t1;
|
||||
d = c; c = b; b = a; a = t1 + t2;
|
||||
}
|
||||
|
||||
iv[0] += a; iv[1] += b; iv[2] += c; iv[3] += d;
|
||||
iv[4] += e; iv[5] += f; iv[6] += g; iv[7] += h;
|
||||
}
|
||||
74
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/utils.c
Normal file
74
lib/NimBLE-Arduino/src/nimble/ext/tinycrypt/src/utils.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/* utils.c - TinyCrypt platform-dependent run-time operations */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - 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.
|
||||
*
|
||||
* - Neither the name of Intel Corporation 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 AND CONTRIBUTORS "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 OWNER OR CONTRIBUTORS 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 "../include/tinycrypt/utils.h"
|
||||
#include "../include/tinycrypt/constants.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MASK_TWENTY_SEVEN 0x1b
|
||||
|
||||
unsigned int _copy(uint8_t *to, unsigned int to_len,
|
||||
const uint8_t *from, unsigned int from_len)
|
||||
{
|
||||
if (from_len <= to_len) {
|
||||
(void)memcpy(to, from, from_len);
|
||||
return from_len;
|
||||
} else {
|
||||
return TC_CRYPTO_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
void _set(void *to, uint8_t val, unsigned int len)
|
||||
{
|
||||
(void)memset(to, val, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Doubles the value of a byte for values up to 127.
|
||||
*/
|
||||
uint8_t _double_byte(uint8_t a)
|
||||
{
|
||||
return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN));
|
||||
}
|
||||
|
||||
int _compare(const uint8_t *a, const uint8_t *b, size_t size)
|
||||
{
|
||||
const uint8_t *tempa = a;
|
||||
const uint8_t *tempb = b;
|
||||
uint8_t result = 0;
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
result |= tempa[i] ^ tempb[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_HW_
|
||||
#define H_BLE_HW_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
|
||||
|
||||
#if defined(ARCH_sim)
|
||||
#define BLE_USES_HW_WHITELIST (0)
|
||||
#else
|
||||
#define BLE_USES_HW_WHITELIST MYNEWT_VAL(BLE_HW_WHITELIST_ENABLE)
|
||||
#endif
|
||||
|
||||
/* Returns the number of hw whitelist elements */
|
||||
uint8_t ble_hw_whitelist_size(void);
|
||||
|
||||
/* Clear the whitelist */
|
||||
void ble_hw_whitelist_clear(void);
|
||||
|
||||
/* Remove a device from the hw whitelist */
|
||||
void ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type);
|
||||
|
||||
/* Add a device to the hw whitelist */
|
||||
int ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type);
|
||||
|
||||
/* Enable hw whitelisting */
|
||||
void ble_hw_whitelist_enable(void);
|
||||
|
||||
/* Enable hw whitelisting */
|
||||
void ble_hw_whitelist_disable(void);
|
||||
|
||||
/* Boolean function returning true if address matches a whitelist entry */
|
||||
int ble_hw_whitelist_match(void);
|
||||
|
||||
/* Encrypt data */
|
||||
struct ble_encryption_block;
|
||||
int ble_hw_encrypt_block(struct ble_encryption_block *ecb);
|
||||
|
||||
/* Random number generation */
|
||||
typedef void (*ble_rng_isr_cb_t)(uint8_t rnum);
|
||||
int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias);
|
||||
|
||||
/**
|
||||
* Start the random number generator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int ble_hw_rng_start(void);
|
||||
|
||||
/**
|
||||
* Stop the random generator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int ble_hw_rng_stop(void);
|
||||
|
||||
/**
|
||||
* Read the random number generator.
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t ble_hw_rng_read(void);
|
||||
|
||||
/* Clear the resolving list*/
|
||||
void ble_hw_resolv_list_clear(void);
|
||||
|
||||
/* Add a device to the hw resolving list */
|
||||
int ble_hw_resolv_list_add(uint8_t *irk);
|
||||
|
||||
/* Remove a device from the hw resolving list */
|
||||
void ble_hw_resolv_list_rmv(int index);
|
||||
|
||||
/* Returns the size of the whitelist in HW */
|
||||
uint8_t ble_hw_resolv_list_size(void);
|
||||
|
||||
/* Enable the resolving list */
|
||||
void ble_hw_resolv_list_enable(void);
|
||||
|
||||
/* Disables resolving list devices */
|
||||
void ble_hw_resolv_list_disable(void);
|
||||
|
||||
/* Returns index of resolved address; -1 if not resolved */
|
||||
int ble_hw_resolv_list_match(void);
|
||||
|
||||
/* Returns public device address or -1 if not present */
|
||||
int ble_hw_get_public_addr(ble_addr_t *addr);
|
||||
|
||||
/* Returns random static address or -1 if not present */
|
||||
int ble_hw_get_static_addr(ble_addr_t *addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_HW_ */
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_
|
||||
#define H_BLE_LL_
|
||||
|
||||
#include "nimble/porting/nimble/include/stats/stats.h"
|
||||
#include "nimble/porting/nimble/include/os/os_cputime.h"
|
||||
#include "nimble/nimble/include/nimble/nimble_opt.h"
|
||||
#include "nimble/nimble/include/nimble/nimble_npl.h"
|
||||
#include "ble_phy.h"
|
||||
|
||||
#ifdef MYNEWT
|
||||
#include "./ble_ll_ctrl.h"
|
||||
#include "hal/hal_system.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
|
||||
#error 32.768kHz clock required
|
||||
#endif
|
||||
|
||||
#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT)
|
||||
#ifdef NDEBUG
|
||||
#define BLE_LL_ASSERT(cond) (void(0))
|
||||
#else
|
||||
#define BLE_LL_ASSERT(cond) \
|
||||
if (!(cond)) { \
|
||||
if (hal_debugger_connected()) { \
|
||||
assert(0);\
|
||||
} else {\
|
||||
ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \
|
||||
while(1) {}\
|
||||
}\
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define BLE_LL_ASSERT(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
|
||||
#define BLE_LL_BT5_PHY_SUPPORTED (1)
|
||||
#else
|
||||
#define BLE_LL_BT5_PHY_SUPPORTED (0)
|
||||
#endif
|
||||
|
||||
/* Controller revision. */
|
||||
#define BLE_LL_SUB_VERS_NR (0x0000)
|
||||
|
||||
/* Timing jitter as per spec is +/16 usecs */
|
||||
#define BLE_LL_JITTER_USECS (16)
|
||||
|
||||
/* Packet queue header definition */
|
||||
STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr);
|
||||
|
||||
/*
|
||||
* Global Link Layer data object. There is only one Link Layer data object
|
||||
* per controller although there may be many instances of the link layer state
|
||||
* machine running.
|
||||
*/
|
||||
struct ble_ll_obj
|
||||
{
|
||||
/* Supported features */
|
||||
uint64_t ll_supp_features;
|
||||
|
||||
/* Current Link Layer state */
|
||||
uint8_t ll_state;
|
||||
|
||||
/* Number of ACL data packets supported */
|
||||
uint8_t ll_num_acl_pkts;
|
||||
|
||||
/* ACL data packet size */
|
||||
uint16_t ll_acl_pkt_size;
|
||||
|
||||
/* Preferred PHY's */
|
||||
uint8_t ll_pref_tx_phys;
|
||||
uint8_t ll_pref_rx_phys;
|
||||
|
||||
/* Task event queue */
|
||||
struct ble_npl_eventq ll_evq;
|
||||
|
||||
/* Wait for response timer */
|
||||
struct hal_timer ll_wfr_timer;
|
||||
|
||||
/* Packet receive queue (and event). Holds received packets from PHY */
|
||||
struct ble_npl_event ll_rx_pkt_ev;
|
||||
struct ble_ll_pkt_q ll_rx_pkt_q;
|
||||
|
||||
/* Packet transmit queue */
|
||||
struct ble_npl_event ll_tx_pkt_ev;
|
||||
struct ble_ll_pkt_q ll_tx_pkt_q;
|
||||
|
||||
/* Data buffer overflow event */
|
||||
struct ble_npl_event ll_dbuf_overflow_ev;
|
||||
|
||||
/* Number of completed packets event */
|
||||
struct ble_npl_event ll_comp_pkt_ev;
|
||||
|
||||
/* HW error callout */
|
||||
struct ble_npl_callout ll_hw_err_timer;
|
||||
};
|
||||
extern struct ble_ll_obj g_ble_ll_data;
|
||||
|
||||
/* Link layer statistics */
|
||||
STATS_SECT_START(ble_ll_stats)
|
||||
STATS_SECT_ENTRY(hci_cmds)
|
||||
STATS_SECT_ENTRY(hci_cmd_errs)
|
||||
STATS_SECT_ENTRY(hci_events_sent)
|
||||
STATS_SECT_ENTRY(bad_ll_state)
|
||||
STATS_SECT_ENTRY(bad_acl_hdr)
|
||||
STATS_SECT_ENTRY(no_bufs)
|
||||
STATS_SECT_ENTRY(rx_adv_pdu_crc_ok)
|
||||
STATS_SECT_ENTRY(rx_adv_pdu_crc_err)
|
||||
STATS_SECT_ENTRY(rx_adv_bytes_crc_ok)
|
||||
STATS_SECT_ENTRY(rx_adv_bytes_crc_err)
|
||||
STATS_SECT_ENTRY(rx_data_pdu_crc_ok)
|
||||
STATS_SECT_ENTRY(rx_data_pdu_crc_err)
|
||||
STATS_SECT_ENTRY(rx_data_bytes_crc_ok)
|
||||
STATS_SECT_ENTRY(rx_data_bytes_crc_err)
|
||||
STATS_SECT_ENTRY(rx_adv_malformed_pkts)
|
||||
STATS_SECT_ENTRY(rx_adv_ind)
|
||||
STATS_SECT_ENTRY(rx_adv_direct_ind)
|
||||
STATS_SECT_ENTRY(rx_adv_nonconn_ind)
|
||||
STATS_SECT_ENTRY(rx_adv_ext_ind)
|
||||
STATS_SECT_ENTRY(rx_scan_reqs)
|
||||
STATS_SECT_ENTRY(rx_scan_rsps)
|
||||
STATS_SECT_ENTRY(rx_connect_reqs)
|
||||
STATS_SECT_ENTRY(rx_scan_ind)
|
||||
STATS_SECT_ENTRY(rx_aux_connect_rsp)
|
||||
STATS_SECT_ENTRY(adv_txg)
|
||||
STATS_SECT_ENTRY(adv_late_starts)
|
||||
STATS_SECT_ENTRY(adv_resched_pdu_fail)
|
||||
STATS_SECT_ENTRY(adv_drop_event)
|
||||
STATS_SECT_ENTRY(sched_state_conn_errs)
|
||||
STATS_SECT_ENTRY(sched_state_adv_errs)
|
||||
STATS_SECT_ENTRY(scan_starts)
|
||||
STATS_SECT_ENTRY(scan_stops)
|
||||
STATS_SECT_ENTRY(scan_req_txf)
|
||||
STATS_SECT_ENTRY(scan_req_txg)
|
||||
STATS_SECT_ENTRY(scan_rsp_txg)
|
||||
STATS_SECT_ENTRY(aux_missed_adv)
|
||||
STATS_SECT_ENTRY(aux_scheduled)
|
||||
STATS_SECT_ENTRY(aux_received)
|
||||
STATS_SECT_ENTRY(aux_fired_for_read)
|
||||
STATS_SECT_ENTRY(aux_allocated)
|
||||
STATS_SECT_ENTRY(aux_freed)
|
||||
STATS_SECT_ENTRY(aux_sched_cb)
|
||||
STATS_SECT_ENTRY(aux_conn_req_tx)
|
||||
STATS_SECT_ENTRY(aux_conn_rsp_tx)
|
||||
STATS_SECT_ENTRY(aux_conn_rsp_err)
|
||||
STATS_SECT_ENTRY(aux_scan_req_tx)
|
||||
STATS_SECT_ENTRY(aux_scan_rsp_err)
|
||||
STATS_SECT_ENTRY(aux_chain_cnt)
|
||||
STATS_SECT_ENTRY(aux_chain_err)
|
||||
STATS_SECT_ENTRY(aux_scan_drop)
|
||||
STATS_SECT_ENTRY(adv_evt_dropped)
|
||||
STATS_SECT_ENTRY(scan_timer_stopped)
|
||||
STATS_SECT_ENTRY(scan_timer_restarted)
|
||||
STATS_SECT_ENTRY(periodic_adv_drop_event)
|
||||
STATS_SECT_ENTRY(periodic_chain_drop_event)
|
||||
STATS_SECT_ENTRY(sync_event_failed)
|
||||
STATS_SECT_ENTRY(sync_received)
|
||||
STATS_SECT_ENTRY(sync_chain_failed)
|
||||
STATS_SECT_ENTRY(sync_missed_err)
|
||||
STATS_SECT_ENTRY(sync_crc_err)
|
||||
STATS_SECT_ENTRY(sync_rx_buf_err)
|
||||
STATS_SECT_ENTRY(sync_scheduled)
|
||||
STATS_SECT_ENTRY(sched_state_sync_errs)
|
||||
STATS_SECT_ENTRY(sched_invalid_pdu)
|
||||
STATS_SECT_END
|
||||
extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats;
|
||||
|
||||
/* States */
|
||||
#define BLE_LL_STATE_STANDBY (0)
|
||||
#define BLE_LL_STATE_ADV (1)
|
||||
#define BLE_LL_STATE_SCANNING (2)
|
||||
#define BLE_LL_STATE_INITIATING (3)
|
||||
#define BLE_LL_STATE_CONNECTION (4)
|
||||
#define BLE_LL_STATE_DTM (5)
|
||||
#define BLE_LL_STATE_SYNC (6)
|
||||
|
||||
/* LL Features */
|
||||
#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001)
|
||||
#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000002)
|
||||
#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000004)
|
||||
#define BLE_LL_FEAT_SLAVE_INIT (0x0000000008)
|
||||
#define BLE_LL_FEAT_LE_PING (0x0000000010)
|
||||
#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000020)
|
||||
#define BLE_LL_FEAT_LL_PRIVACY (0x0000000040)
|
||||
#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000080)
|
||||
#define BLE_LL_FEAT_LE_2M_PHY (0x0000000100)
|
||||
#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000200)
|
||||
#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000400)
|
||||
#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000800)
|
||||
#define BLE_LL_FEAT_EXT_ADV (0x0000001000)
|
||||
#define BLE_LL_FEAT_PERIODIC_ADV (0x0000002000)
|
||||
#define BLE_LL_FEAT_CSA2 (0x0000004000)
|
||||
#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000008000)
|
||||
#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000010000)
|
||||
#define BLE_LL_FEAT_CTE_REQ (0x0000020000)
|
||||
#define BLE_LL_FEAT_CTE_RSP (0x0000040000)
|
||||
#define BLE_LL_FEAT_CTE_TX (0x0000080000)
|
||||
#define BLE_LL_FEAT_CTE_RX (0x0000100000)
|
||||
#define BLE_LL_FEAT_CTE_AOD (0x0000200000)
|
||||
#define BLE_LL_FEAT_CTE_AOA (0x0000400000)
|
||||
#define BLE_LL_FEAT_CTE_RECV (0x0000800000)
|
||||
#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0001000000)
|
||||
#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0002000000)
|
||||
#define BLE_LL_FEAT_SCA_UPDATE (0x0004000000)
|
||||
#define BLE_LL_FEAT_REM_PKEY (0x0008000000)
|
||||
#define BLE_LL_FEAT_CIS_MASTER (0x0010000000)
|
||||
#define BLE_LL_FEAT_CIS_SLAVE (0x0020000000)
|
||||
#define BLE_LL_FEAT_ISO_BROADCASTER (0x0040000000)
|
||||
#define BLE_LL_FEAT_SYNC_RECV (0x0080000000)
|
||||
#define BLE_LL_FEAT_ISO_HOST_SUPPORT (0x0100000000)
|
||||
#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0200000000)
|
||||
#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0400000000)
|
||||
#define BLE_LL_FEAT_PATH_LOSS_MON (0x0800000000)
|
||||
|
||||
/* This is initial mask, so if feature exchange will not happen,
|
||||
* but host will want to use this procedure, we will try. If not
|
||||
* succeed, feature bit will be cleared.
|
||||
* Look at LL Features above to find out what is allowed
|
||||
*/
|
||||
#define BLE_LL_CONN_INITIAL_FEATURES (0x00000022)
|
||||
#define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature))
|
||||
|
||||
/* All the features which can be controlled by the Host */
|
||||
#define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_ISO_HOST_SUPPORT)
|
||||
|
||||
/* LL timing */
|
||||
#define BLE_LL_IFS (150) /* usecs */
|
||||
#define BLE_LL_MAFS (300) /* usecs */
|
||||
|
||||
/*
|
||||
* BLE LL device address. Note that element 0 of the array is the LSB and
|
||||
* is sent over the air first. Byte 5 is the MSB and is the last one sent over
|
||||
* the air.
|
||||
*/
|
||||
#define BLE_DEV_ADDR_LEN (6) /* bytes */
|
||||
|
||||
struct ble_dev_addr
|
||||
{
|
||||
uint8_t u8[BLE_DEV_ADDR_LEN];
|
||||
};
|
||||
|
||||
#define BLE_IS_DEV_ADDR_STATIC(addr) ((addr->u8[5] & 0xc0) == 0xc0)
|
||||
#define BLE_IS_DEV_ADDR_RESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x40)
|
||||
#define BLE_IS_DEV_ADDR_UNRESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x00)
|
||||
|
||||
/*
|
||||
* LL packet format
|
||||
*
|
||||
* -> Preamble (1/2 bytes)
|
||||
* -> Access Address (4 bytes)
|
||||
* -> PDU (2 to 257 octets)
|
||||
* -> CRC (3 bytes)
|
||||
*/
|
||||
#define BLE_LL_PREAMBLE_LEN (1)
|
||||
#define BLE_LL_ACC_ADDR_LEN (4)
|
||||
#define BLE_LL_CRC_LEN (3)
|
||||
#define BLE_LL_PDU_HDR_LEN (2)
|
||||
#define BLE_LL_MAX_PAYLOAD_LEN (255)
|
||||
#define BLE_LL_MIN_PDU_LEN (BLE_LL_PDU_HDR_LEN)
|
||||
#define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN))
|
||||
#define BLE_LL_CRCINIT_ADV (0x555555)
|
||||
|
||||
/* Access address for advertising channels */
|
||||
#define BLE_ACCESS_ADDR_ADV (0x8E89BED6)
|
||||
|
||||
/*
|
||||
* Advertising PDU format:
|
||||
* -> 2 byte header
|
||||
* -> LSB contains pdu type, txadd and rxadd bits.
|
||||
* -> MSB contains length (6 bits). Length is length of payload. Does
|
||||
* not include the header length itself.
|
||||
* -> Payload (max 37 bytes)
|
||||
*/
|
||||
#define BLE_ADV_PDU_HDR_TYPE_MASK (0x0F)
|
||||
#define BLE_ADV_PDU_HDR_CHSEL_MASK (0x20)
|
||||
#define BLE_ADV_PDU_HDR_TXADD_MASK (0x40)
|
||||
#define BLE_ADV_PDU_HDR_RXADD_MASK (0x80)
|
||||
|
||||
/* Advertising channel PDU types */
|
||||
#define BLE_ADV_PDU_TYPE_ADV_IND (0)
|
||||
#define BLE_ADV_PDU_TYPE_ADV_DIRECT_IND (1)
|
||||
#define BLE_ADV_PDU_TYPE_ADV_NONCONN_IND (2)
|
||||
#define BLE_ADV_PDU_TYPE_SCAN_REQ (3)
|
||||
#define BLE_ADV_PDU_TYPE_SCAN_RSP (4)
|
||||
#define BLE_ADV_PDU_TYPE_CONNECT_IND (5)
|
||||
#define BLE_ADV_PDU_TYPE_ADV_SCAN_IND (6)
|
||||
#define BLE_ADV_PDU_TYPE_ADV_EXT_IND (7)
|
||||
#define BLE_ADV_PDU_TYPE_AUX_ADV_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
|
||||
#define BLE_ADV_PDU_TYPE_AUX_SCAN_RSP BLE_ADV_PDU_TYPE_ADV_EXT_IND
|
||||
#define BLE_ADV_PDU_TYPE_AUX_SYNC_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
|
||||
#define BLE_ADV_PDU_TYPE_AUX_CHAIN_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
|
||||
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ BLE_ADV_PDU_TYPE_CONNECT_IND
|
||||
#define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ
|
||||
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8)
|
||||
|
||||
/* Extended Header Length (6b) + AdvMode (2b) */
|
||||
#define BLE_LL_EXT_ADV_HDR_LEN (1)
|
||||
|
||||
#define BLE_LL_EXT_ADV_ADVA_BIT (0)
|
||||
#define BLE_LL_EXT_ADV_TARGETA_BIT (1)
|
||||
#define BLE_LL_EXT_ADV_CTE_INFO_BIT (2)
|
||||
#define BLE_LL_EXT_ADV_DATA_INFO_BIT (3)
|
||||
#define BLE_LL_EXT_ADV_AUX_PTR_BIT (4)
|
||||
#define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5)
|
||||
#define BLE_LL_EXT_ADV_TX_POWER_BIT (6)
|
||||
|
||||
#define BLE_LL_EXT_ADV_FLAGS_SIZE (1)
|
||||
#define BLE_LL_EXT_ADV_ADVA_SIZE (6)
|
||||
#define BLE_LL_EXT_ADV_TARGETA_SIZE (6)
|
||||
#define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2)
|
||||
#define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3)
|
||||
#define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18)
|
||||
#define BLE_LL_EXT_ADV_TX_POWER_SIZE (1)
|
||||
|
||||
#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00)
|
||||
#define BLE_LL_EXT_ADV_MODE_CONN (0x01)
|
||||
#define BLE_LL_EXT_ADV_MODE_SCAN (0x02)
|
||||
|
||||
/* If Channel Selection Algorithm #2 is supported */
|
||||
#define BLE_ADV_PDU_HDR_CHSEL (0x20)
|
||||
|
||||
/*
|
||||
* TxAdd and RxAdd bit definitions. A 0 is a public address; a 1 is a
|
||||
* random address.
|
||||
*/
|
||||
#define BLE_ADV_PDU_HDR_TXADD_RAND (0x40)
|
||||
#define BLE_ADV_PDU_HDR_RXADD_RAND (0x80)
|
||||
|
||||
/*
|
||||
* Data Channel format
|
||||
*
|
||||
* -> Header (2 bytes)
|
||||
* -> LSB contains llid, nesn, sn and md
|
||||
* -> MSB contains length (8 bits)
|
||||
* -> Payload (0 to 251)
|
||||
* -> MIC (0 or 4 bytes)
|
||||
*/
|
||||
#define BLE_LL_DATA_HDR_LLID_MASK (0x03)
|
||||
#define BLE_LL_DATA_HDR_NESN_MASK (0x04)
|
||||
#define BLE_LL_DATA_HDR_SN_MASK (0x08)
|
||||
#define BLE_LL_DATA_HDR_MD_MASK (0x10)
|
||||
#define BLE_LL_DATA_HDR_RSRVD_MASK (0xE0)
|
||||
#define BLE_LL_DATA_PDU_MAX_PYLD (251)
|
||||
#define BLE_LL_DATA_MIC_LEN (4)
|
||||
|
||||
/* LLID definitions */
|
||||
#define BLE_LL_LLID_RSRVD (0)
|
||||
#define BLE_LL_LLID_DATA_FRAG (1)
|
||||
#define BLE_LL_LLID_DATA_START (2)
|
||||
#define BLE_LL_LLID_CTRL (3)
|
||||
|
||||
/*
|
||||
* CONNECT_REQ
|
||||
* -> InitA (6 bytes)
|
||||
* -> AdvA (6 bytes)
|
||||
* -> LLData (22 bytes)
|
||||
* -> Access address (4 bytes)
|
||||
* -> CRC initialize (3 bytes)
|
||||
* -> WinSize (1 byte)
|
||||
* -> WinOffset (2 bytes)
|
||||
* -> Interval (2 bytes)
|
||||
* -> Latency (2 bytes)
|
||||
* -> Timeout (2 bytes)
|
||||
* -> Channel Map (5 bytes)
|
||||
* -> Hop Increment (5 bits)
|
||||
* -> SCA (3 bits)
|
||||
*
|
||||
* InitA is the initiators public (TxAdd=0) or random (TxAdd=1) address.
|
||||
* AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address.
|
||||
* LLData contains connection request data.
|
||||
* aa: Link Layer's access address
|
||||
* crc_init: The CRC initialization value used for CRC calculation.
|
||||
* winsize: The transmit window size = winsize * 1.25 msecs
|
||||
* winoffset: The transmit window offset = winoffset * 1.25 msecs
|
||||
* interval: The connection interval = interval * 1.25 msecs.
|
||||
* latency: connection slave latency = latency
|
||||
* timeout: Connection supervision timeout = timeout * 10 msecs.
|
||||
* chanmap: contains channel mapping indicating used and unused data
|
||||
* channels. Only bits that are 1 are usable. LSB is channel 0.
|
||||
* hop_inc: Hop increment used for frequency hopping. Random value in
|
||||
* range of 5 to 16.
|
||||
*/
|
||||
#define BLE_CONNECT_REQ_LEN (34)
|
||||
#define BLE_CONNECT_REQ_PDU_LEN (BLE_CONNECT_REQ_LEN + BLE_LL_PDU_HDR_LEN)
|
||||
|
||||
#define BLE_SCAN_REQ_LEN (12)
|
||||
#define BLE_SCAN_RSP_MAX_LEN (37)
|
||||
#define BLE_SCAN_RSP_MAX_EXT_LEN (251)
|
||||
|
||||
#define BLE_LL_ADDR_SUBTYPE_IDENTITY (0)
|
||||
#define BLE_LL_ADDR_SUBTYPE_RPA (1)
|
||||
#define BLE_LL_ADDR_SUBTYPE_NRPA (2)
|
||||
|
||||
/*--- External API ---*/
|
||||
/* Initialize the Link Layer */
|
||||
void ble_ll_init(void);
|
||||
|
||||
/* Reset the Link Layer */
|
||||
int ble_ll_reset(void);
|
||||
|
||||
int ble_ll_is_valid_public_addr(const uint8_t *addr);
|
||||
|
||||
/* 'Boolean' function returning true if address is a valid random address */
|
||||
int ble_ll_is_valid_random_addr(const uint8_t *addr);
|
||||
|
||||
/*
|
||||
* Check if given own_addr_type is valid for current controller configuration
|
||||
* given the random address provided (when applicable)
|
||||
*/
|
||||
int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type,
|
||||
const uint8_t *random_addr);
|
||||
|
||||
/* Calculate the amount of time in microseconds a PDU with payload length of
|
||||
* 'payload_len' will take to transmit on a PHY 'phy_mode'. */
|
||||
uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode);
|
||||
|
||||
/* Calculate maximum octets of PDU payload which can be transmitted during
|
||||
* 'usecs' on a PHY 'phy_mode'. */
|
||||
uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode);
|
||||
|
||||
/* Is this address a resolvable private address? */
|
||||
int ble_ll_is_rpa(const uint8_t *addr, uint8_t addr_type);
|
||||
|
||||
int ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type);
|
||||
|
||||
/* Is this address an identity address? */
|
||||
int ble_ll_addr_is_id(uint8_t *addr, uint8_t addr_type);
|
||||
|
||||
/* Is 'addr' our device address? 'addr_type' is public (0) or random (!=0) */
|
||||
int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
|
||||
|
||||
/* Get identity address 'addr_type' is public (0) or random (!=0) */
|
||||
uint8_t *ble_ll_get_our_devaddr(uint8_t addr_type);
|
||||
|
||||
/**
|
||||
* Called to put a packet on the Link Layer transmit packet queue.
|
||||
*
|
||||
* @param txpdu Pointer to transmit packet
|
||||
*/
|
||||
void ble_ll_acl_data_in(struct os_mbuf *txpkt);
|
||||
|
||||
/**
|
||||
* Allocates mbuf for received PDU
|
||||
*
|
||||
* This allocated mbuf (may be chained if necessary) that has capacity large
|
||||
* enough to store received PDU of given length. It does not set mbufs length
|
||||
* as this has to be done by PHY when copying data.
|
||||
*
|
||||
* @param len Length of PDU, including PDU header and excluding MIC (if encrypted)
|
||||
*
|
||||
* @return mbuf large enough to store received PDU on success
|
||||
* NULL on failure (oom)
|
||||
*/
|
||||
struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len);
|
||||
|
||||
/* Tell the Link Layer there has been a data buffer overflow */
|
||||
void ble_ll_data_buffer_overflow(void);
|
||||
|
||||
/* Tell the link layer there has been a hardware error */
|
||||
void ble_ll_hw_error(void);
|
||||
|
||||
/*--- PHY interfaces ---*/
|
||||
struct ble_mbuf_hdr;
|
||||
|
||||
/* Called by the PHY when a packet has started */
|
||||
int ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *hdr);
|
||||
|
||||
/* Called by the PHY when a packet reception ends */
|
||||
int ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
|
||||
|
||||
/* Helper callback to tx mbuf using ble_phy_tx() */
|
||||
uint8_t ble_ll_tx_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
|
||||
uint8_t ble_ll_tx_flat_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
|
||||
|
||||
/*--- Controller API ---*/
|
||||
void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr);
|
||||
|
||||
/* Set the link layer state */
|
||||
void ble_ll_state_set(uint8_t ll_state);
|
||||
|
||||
/* Get the link layer state */
|
||||
uint8_t ble_ll_state_get(void);
|
||||
|
||||
/* Send an event to LL task */
|
||||
void ble_ll_event_send(struct ble_npl_event *ev);
|
||||
|
||||
/* Hand received pdu's to LL task */
|
||||
void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu);
|
||||
|
||||
/*
|
||||
* Set public address
|
||||
*
|
||||
* This can be used to set controller public address from vendor specific storage,
|
||||
* usually should be done in hal_bsp_init().
|
||||
* Shall be *only* called before LL is initialized, i.e. before sysinit stage.
|
||||
*/
|
||||
int ble_ll_set_public_addr(const uint8_t *addr);
|
||||
|
||||
/* Set random address */
|
||||
int ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext);
|
||||
|
||||
/* Wait for response timer expiration callback */
|
||||
void ble_ll_wfr_timer_exp(void *arg);
|
||||
|
||||
/* Read set of features supported by the Link Layer */
|
||||
uint64_t ble_ll_read_supp_features(void);
|
||||
|
||||
/* Set host supported features */
|
||||
int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
/* Read set of states supported by the Link Layer */
|
||||
uint64_t ble_ll_read_supp_states(void);
|
||||
|
||||
/* Check if octets and time are valid. Returns 0 if not valid */
|
||||
int ble_ll_chk_txrx_octets(uint16_t octets);
|
||||
int ble_ll_chk_txrx_time(uint16_t time);
|
||||
|
||||
/* Random numbers */
|
||||
int ble_ll_rand_init(void);
|
||||
void ble_ll_rand_sample(uint8_t rnum);
|
||||
int ble_ll_rand_data_get(uint8_t *buf, uint8_t len);
|
||||
void ble_ll_rand_prand_get(uint8_t *prand);
|
||||
int ble_ll_rand_start(void);
|
||||
|
||||
static inline int
|
||||
ble_ll_get_addr_type(uint8_t txrxflag)
|
||||
{
|
||||
if (txrxflag) {
|
||||
return BLE_HCI_ADV_OWN_ADDR_RANDOM;
|
||||
}
|
||||
return BLE_HCI_ADV_OWN_ADDR_PUBLIC;
|
||||
}
|
||||
|
||||
/* Convert usecs to ticks and round up to nearest tick */
|
||||
static inline uint32_t
|
||||
ble_ll_usecs_to_ticks_round_up(uint32_t usecs)
|
||||
{
|
||||
return os_cputime_usecs_to_ticks(usecs + 30);
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
|
||||
/* LTK 0x4C68384139F574D836BCF34E9DFB01BF */
|
||||
extern const uint8_t g_bletest_LTK[];
|
||||
extern uint16_t g_bletest_EDIV;
|
||||
extern uint64_t g_bletest_RAND;
|
||||
extern uint64_t g_bletest_SKDm;
|
||||
extern uint64_t g_bletest_SKDs;
|
||||
extern uint32_t g_bletest_IVm;
|
||||
extern uint32_t g_bletest_IVs;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_DTM)
|
||||
void ble_ll_dtm_init(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_LL_ */
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_ADV_
|
||||
#define H_BLE_LL_ADV_
|
||||
|
||||
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ADV event timing
|
||||
* T_advEvent = advInterval + advDelay
|
||||
*
|
||||
* advInterval: increments of 625 usecs
|
||||
* advDelay: RAND[0, 10] msecs
|
||||
*
|
||||
*/
|
||||
#define BLE_LL_ADV_ITVL (625) /* usecs */
|
||||
#define BLE_LL_ADV_ITVL_MIN (32) /* units */
|
||||
#define BLE_LL_ADV_ITVL_MAX (16384) /* units */
|
||||
#define BLE_LL_ADV_ITVL_MS_MIN (20) /* msecs */
|
||||
#define BLE_LL_ADV_ITVL_MS_MAX (10240) /* msecs */
|
||||
#define BLE_LL_ADV_ITVL_SCAN_MIN (160) /* units */
|
||||
#define BLE_LL_ADV_ITVL_SCAN_MS_MIN (100) /* msecs */
|
||||
#define BLE_LL_ADV_ITVL_NONCONN_MS_MIN (100) /* msecs */
|
||||
#define BLE_LL_ADV_DELAY_MS_MIN (0) /* msecs */
|
||||
#define BLE_LL_ADV_DELAY_MS_MAX (10) /* msecs */
|
||||
#define BLE_LL_ADV_PDU_ITVL_LD_MS_MAX (10) /* msecs */
|
||||
#define BLE_LL_ADV_PDU_ITVL_HD_MS_MAX (3750) /* usecs */
|
||||
#define BLE_LL_ADV_STATE_HD_MAX (1280) /* msecs */
|
||||
#define BLE_LL_ADV_PERIODIC_ITVL (1250) /* usecs */
|
||||
|
||||
/* Maximum advertisement data length */
|
||||
#define BLE_ADV_LEGACY_DATA_MAX_LEN (31)
|
||||
#define BLE_ADV_LEGACY_MAX_PKT_LEN (37)
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
|
||||
#define BLE_ADV_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)
|
||||
#else
|
||||
#define BLE_ADV_DATA_MAX_LEN BLE_ADV_LEGACY_DATA_MAX_LEN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ADV_IND
|
||||
* -> AdvA (6 bytes)
|
||||
* -> AdvData (0 - 31 bytes)
|
||||
*
|
||||
* The advertising address (AdvA) is a public address (TxAdd=0) or random
|
||||
* address (TxAdd = 1)
|
||||
*/
|
||||
#define BLE_ADV_IND_MIN_LEN (6)
|
||||
#define BLE_ADV_IND_MAX_LEN (37)
|
||||
|
||||
/*
|
||||
* ADV_DIRECT_IND
|
||||
* -> AdvA (6 bytes)
|
||||
* -> InitA (6 bytes)
|
||||
*
|
||||
* AdvA is the advertisers public address (TxAdd=0) or random address
|
||||
* (TxAdd = 1).
|
||||
*
|
||||
* InitA is the initiators public or random address. This is the address
|
||||
* to which this packet is addressed.
|
||||
*
|
||||
*/
|
||||
#define BLE_ADV_DIRECT_IND_LEN (12)
|
||||
|
||||
/*
|
||||
* ADV_NONCONN_IND
|
||||
* -> AdvA (6 bytes)
|
||||
* -> AdvData (0 - 31 bytes)
|
||||
*
|
||||
* The advertising address (AdvA) is a public address (TxAdd=0) or random
|
||||
* address (TxAdd = 1)
|
||||
*
|
||||
*/
|
||||
#define BLE_ADV_NONCONN_IND_MIN_LEN (6)
|
||||
#define BLE_ADV_NONCONN_IND_MAX_LEN (37)
|
||||
|
||||
/*
|
||||
* ADV_SCAN_IND
|
||||
* -> AdvA (6 bytes)
|
||||
* -> AdvData (0 - 31 bytes)
|
||||
*
|
||||
* The advertising address (AdvA) is a public address (TxAdd=0) or random
|
||||
* address (TxAdd = 1)
|
||||
*
|
||||
*/
|
||||
#define BLE_ADV_SCAN_IND_MIN_LEN (6)
|
||||
#define BLE_ADV_SCAN_IND_MAX_LEN (37)
|
||||
|
||||
/*---- HCI ----*/
|
||||
struct ble_ll_adv_sm;
|
||||
struct ble_ll_conn_sm;
|
||||
|
||||
/* Start an advertiser */
|
||||
int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type,
|
||||
uint8_t *init_addr, uint16_t adv_itvl, void *handle);
|
||||
|
||||
/* Start or stop advertising */
|
||||
int ble_ll_hci_adv_set_enable(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
/* Set legacy advertising data */
|
||||
int ble_ll_hci_set_adv_data(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
/* Set scan response data */
|
||||
int ble_ll_hci_set_scan_rsp_data(const uint8_t *cmd, uint8_t cmd_len);
|
||||
|
||||
/* Set advertising parameters */
|
||||
int ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
/* Read advertising channel power */
|
||||
int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen);
|
||||
|
||||
/*---- API used by BLE LL ----*/
|
||||
/* Send the connection complete event */
|
||||
void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
|
||||
struct ble_mbuf_hdr *rxhdr);
|
||||
|
||||
/* Returns local resolvable private address */
|
||||
uint8_t *ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm);
|
||||
|
||||
/* Returns peer resolvable private address */
|
||||
uint8_t *ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm);
|
||||
|
||||
/* Called to initialize advertising functionality. */
|
||||
void ble_ll_adv_init(void);
|
||||
|
||||
/* Called when LL wait for response timer expires in advertising state */
|
||||
void ble_ll_adv_wfr_timer_exp(void);
|
||||
|
||||
/* Called to reset the advertiser. */
|
||||
void ble_ll_adv_reset(void);
|
||||
|
||||
/* Called on rx pdu start when in advertising state */
|
||||
int ble_ll_adv_rx_isr_start(uint8_t pdu_type);
|
||||
|
||||
/* Called on rx pdu end when in advertising state */
|
||||
int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok);
|
||||
|
||||
/* Processes received packets at the link layer task */
|
||||
void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
|
||||
struct ble_mbuf_hdr *hdr);
|
||||
|
||||
/* Boolean function denoting whether or not the whitelist can be changed */
|
||||
int ble_ll_adv_can_chg_whitelist(void);
|
||||
|
||||
/*
|
||||
* Called when an advertising event has been removed from the scheduler
|
||||
* without being run.
|
||||
*/
|
||||
void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
|
||||
|
||||
/*
|
||||
* Called when a periodic event has been removed from the scheduler
|
||||
* without being run.
|
||||
*/
|
||||
void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
|
||||
|
||||
/* Called to halt currently running advertising event */
|
||||
void ble_ll_adv_halt(void);
|
||||
|
||||
/* Called to determine if advertising is enabled */
|
||||
uint8_t ble_ll_adv_enabled(void);
|
||||
|
||||
int ble_ll_adv_hci_set_random_addr(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance);
|
||||
int ble_ll_adv_remove(const uint8_t *addr, uint8_t len);
|
||||
int ble_ll_adv_clear_all(void);
|
||||
int ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
|
||||
uint8_t *rspbuf, uint8_t *rsplen);
|
||||
int ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen);
|
||||
int ble_ll_adv_ext_set_scan_rsp(const uint8_t *cmdbuf, uint8_t cmdlen);
|
||||
int ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
int ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len);
|
||||
int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len);
|
||||
|
||||
int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
|
||||
uint8_t *rspbuf, uint8_t *rsplen);
|
||||
|
||||
/* Called to notify adv code about RPA rotation */
|
||||
void ble_ll_adv_rpa_timeout(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_LL_ADV_ */
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_CONN_
|
||||
#define H_BLE_LL_CONN_
|
||||
|
||||
#include "nimble/porting/nimble/include/os/os.h"
|
||||
#include "nimble/nimble/include/nimble/ble.h"
|
||||
#include "nimble/nimble/include/nimble/hci_common.h"
|
||||
#include "nimble/nimble/include/nimble/nimble_npl.h"
|
||||
#include "ble_ll_sched.h"
|
||||
#include "ble_ll_ctrl.h"
|
||||
#include "ble_phy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Roles */
|
||||
#define BLE_LL_CONN_ROLE_NONE (0)
|
||||
#define BLE_LL_CONN_ROLE_MASTER (1)
|
||||
#define BLE_LL_CONN_ROLE_SLAVE (2)
|
||||
|
||||
/* Connection states */
|
||||
#define BLE_LL_CONN_STATE_IDLE (0)
|
||||
#define BLE_LL_CONN_STATE_CREATED (1)
|
||||
#define BLE_LL_CONN_STATE_ESTABLISHED (2)
|
||||
|
||||
/* Channel map size */
|
||||
#define BLE_LL_CONN_CHMAP_LEN (5)
|
||||
|
||||
/* Definitions for source clock accuracy */
|
||||
#define BLE_MASTER_SCA_251_500_PPM (0)
|
||||
#define BLE_MASTER_SCA_151_250_PPM (1)
|
||||
#define BLE_MASTER_SCA_101_150_PPM (2)
|
||||
#define BLE_MASTER_SCA_76_100_PPM (3)
|
||||
#define BLE_MASTER_SCA_51_75_PPM (4)
|
||||
#define BLE_MASTER_SCA_31_50_PPM (5)
|
||||
#define BLE_MASTER_SCA_21_30_PPM (6)
|
||||
#define BLE_MASTER_SCA_0_20_PPM (7)
|
||||
|
||||
/* Definition for RSSI when the RSSI is unknown */
|
||||
#define BLE_LL_CONN_UNKNOWN_RSSI (127)
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
|
||||
/*
|
||||
* Encryption states for a connection
|
||||
*
|
||||
* NOTE: the states are ordered so that we can check to see if the state
|
||||
* is greater than ENCRYPTED. If so, it means that the start or pause
|
||||
* encryption procedure is running and we should not send data pdu's.
|
||||
*/
|
||||
enum conn_enc_state {
|
||||
CONN_ENC_S_UNENCRYPTED = 1,
|
||||
CONN_ENC_S_ENCRYPTED,
|
||||
CONN_ENC_S_ENC_RSP_WAIT,
|
||||
CONN_ENC_S_PAUSE_ENC_RSP_WAIT,
|
||||
CONN_ENC_S_PAUSED,
|
||||
CONN_ENC_S_START_ENC_REQ_WAIT,
|
||||
CONN_ENC_S_START_ENC_RSP_WAIT,
|
||||
CONN_ENC_S_LTK_REQ_WAIT,
|
||||
CONN_ENC_S_LTK_NEG_REPLY
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that the LTK is the key, the SDK is the plain text, and the
|
||||
* session key is the cipher text portion of the encryption block.
|
||||
*
|
||||
* NOTE: we have intentionally violated the specification by making the
|
||||
* transmit and receive packet counters 32-bits as opposed to 39 (as per the
|
||||
* specification). We do this to save code space, ram and calculation time. The
|
||||
* only drawback is that any encrypted connection that sends more than 2^32
|
||||
* packets will suffer a MIC failure and thus be disconnected.
|
||||
*/
|
||||
struct ble_ll_conn_enc_data
|
||||
{
|
||||
uint8_t enc_state;
|
||||
uint8_t tx_encrypted;
|
||||
uint16_t enc_div;
|
||||
uint32_t tx_pkt_cntr;
|
||||
uint32_t rx_pkt_cntr;
|
||||
uint64_t host_rand_num;
|
||||
uint8_t iv[8];
|
||||
struct ble_encryption_block enc_block;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Connection state machine flags. */
|
||||
union ble_ll_conn_sm_flags {
|
||||
struct {
|
||||
uint32_t pkt_rxd:1;
|
||||
uint32_t terminate_ind_txd:1;
|
||||
uint32_t terminate_ind_rxd:1;
|
||||
uint32_t terminate_ind_rxd_acked:1;
|
||||
uint32_t allow_slave_latency:1;
|
||||
uint32_t slave_set_last_anchor:1;
|
||||
uint32_t awaiting_host_reply:1;
|
||||
uint32_t terminate_started:1;
|
||||
uint32_t conn_update_sched:1;
|
||||
uint32_t host_expects_upd_event:1;
|
||||
uint32_t version_ind_sent:1;
|
||||
uint32_t rxd_version_ind:1;
|
||||
uint32_t chanmap_update_scheduled:1;
|
||||
uint32_t conn_empty_pdu_txd:1;
|
||||
uint32_t last_txd_md:1;
|
||||
uint32_t conn_req_txd:1;
|
||||
uint32_t send_ltk_req:1;
|
||||
uint32_t encrypted:1;
|
||||
uint32_t encrypt_chg_sent:1;
|
||||
uint32_t le_ping_supp:1;
|
||||
uint32_t csa2_supp:1;
|
||||
uint32_t host_phy_update: 1;
|
||||
uint32_t phy_update_sched: 1;
|
||||
uint32_t ctrlr_phy_update: 1;
|
||||
uint32_t phy_update_event: 1;
|
||||
uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */
|
||||
uint32_t aux_conn_req: 1;
|
||||
uint32_t rxd_features:1;
|
||||
uint32_t pending_hci_rd_features:1;
|
||||
uint32_t pending_initiate_dle:1;
|
||||
} cfbit;
|
||||
uint32_t conn_flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Structure used for PHY data inside a connection.
|
||||
*
|
||||
* NOTE: the new phy's are the phys we will change to when a phy update
|
||||
* procedure is ongoing and the event counter hits the instant.
|
||||
*
|
||||
* tx_phy_mode: chip specific phy mode for tx
|
||||
* rx_phy_mode: chip specific phy mode for rx
|
||||
* cur_tx_phy: value denoting current tx_phy (not a bitmask!)
|
||||
* cur_rx_phy: value denoting current rx phy (not a bitmask!)
|
||||
* new_tx_phy: value denoting new tx_phy (not a bitmask!)
|
||||
* new_rx_phy: value denoting new rx phy (not a bitmask!)
|
||||
* req_pref_tx_phy: tx phy sent in a phy request (may be different than host)
|
||||
* req_pref_rx_phy: rx phy sent in a phy request (may be different than host)
|
||||
* host_pref_tx_phys: bitmask of preferred transmit PHYs sent by host
|
||||
* host_pref_rx_phys: bitmask of preferred receive PHYs sent by host
|
||||
* phy_options: preferred phy options for coded phy
|
||||
*/
|
||||
struct ble_ll_conn_phy_data
|
||||
{
|
||||
uint32_t tx_phy_mode: 2;
|
||||
uint32_t rx_phy_mode: 2;
|
||||
uint32_t cur_tx_phy: 2;
|
||||
uint32_t cur_rx_phy: 2;
|
||||
uint32_t new_tx_phy: 2;
|
||||
uint32_t new_rx_phy: 2;
|
||||
uint32_t host_pref_tx_phys_mask: 3;
|
||||
uint32_t host_pref_rx_phys_mask: 3;
|
||||
uint32_t req_pref_tx_phys_mask: 3;
|
||||
uint32_t req_pref_rx_phys_mask: 3;
|
||||
uint32_t phy_options: 2;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CONN_CUR_TX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_tx_phy - 1))
|
||||
#define CONN_CUR_RX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_rx_phy - 1))
|
||||
|
||||
struct hci_conn_update
|
||||
{
|
||||
uint16_t handle;
|
||||
uint16_t conn_itvl_min;
|
||||
uint16_t conn_itvl_max;
|
||||
uint16_t conn_latency;
|
||||
uint16_t supervision_timeout;
|
||||
uint16_t min_ce_len;
|
||||
uint16_t max_ce_len;
|
||||
};
|
||||
|
||||
struct hci_ext_conn_params
|
||||
{
|
||||
uint16_t scan_itvl;
|
||||
uint16_t scan_window;
|
||||
uint16_t conn_itvl_min;
|
||||
uint16_t conn_itvl_max;
|
||||
uint16_t conn_latency;
|
||||
uint16_t supervision_timeout;
|
||||
uint16_t min_ce_len;
|
||||
uint16_t max_ce_len;
|
||||
};
|
||||
|
||||
struct hci_ext_create_conn
|
||||
{
|
||||
uint8_t filter_policy;
|
||||
uint8_t own_addr_type;
|
||||
uint8_t peer_addr_type;
|
||||
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
|
||||
uint8_t init_phy_mask;
|
||||
struct hci_ext_conn_params params[3];
|
||||
};
|
||||
|
||||
/* Connection state machine */
|
||||
struct ble_ll_conn_sm
|
||||
{
|
||||
/* Connection state machine flags */
|
||||
union ble_ll_conn_sm_flags csmflags;
|
||||
|
||||
/* Current connection handle, state and role */
|
||||
uint16_t conn_handle;
|
||||
uint8_t conn_state;
|
||||
uint8_t conn_role; /* Can possibly be 1 bit */
|
||||
|
||||
/* RSSI */
|
||||
int8_t conn_rssi;
|
||||
|
||||
/* For privacy */
|
||||
int8_t rpa_index;
|
||||
|
||||
/* Connection data length management */
|
||||
uint8_t max_tx_octets;
|
||||
uint8_t max_rx_octets;
|
||||
uint8_t rem_max_tx_octets;
|
||||
uint8_t rem_max_rx_octets;
|
||||
uint8_t eff_max_tx_octets;
|
||||
uint8_t eff_max_rx_octets;
|
||||
uint16_t max_tx_time;
|
||||
uint16_t max_rx_time;
|
||||
uint16_t rem_max_tx_time;
|
||||
uint16_t rem_max_rx_time;
|
||||
uint16_t eff_max_tx_time;
|
||||
uint16_t eff_max_rx_time;
|
||||
uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE];
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
|
||||
uint16_t host_req_max_tx_time;
|
||||
#endif
|
||||
|
||||
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
|
||||
struct ble_ll_conn_phy_data phy_data;
|
||||
uint16_t phy_instant;
|
||||
uint8_t phy_tx_transition;
|
||||
#endif
|
||||
|
||||
/* Used to calculate data channel index for connection */
|
||||
uint8_t chanmap[BLE_LL_CONN_CHMAP_LEN];
|
||||
uint8_t req_chanmap[BLE_LL_CONN_CHMAP_LEN];
|
||||
uint16_t chanmap_instant;
|
||||
uint16_t channel_id; /* TODO could be union with hop and last chan used */
|
||||
uint8_t hop_inc;
|
||||
uint8_t data_chan_index;
|
||||
uint8_t last_unmapped_chan;
|
||||
uint8_t num_used_chans;
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
|
||||
uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */
|
||||
#endif
|
||||
|
||||
/* Ack/Flow Control */
|
||||
uint8_t tx_seqnum; /* note: can be 1 bit */
|
||||
uint8_t next_exp_seqnum; /* note: can be 1 bit */
|
||||
uint8_t cons_rxd_bad_crc; /* note: can be 1 bit */
|
||||
uint8_t last_rxd_sn; /* note: cant be 1 bit given current code */
|
||||
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
|
||||
only use the MD bit now */
|
||||
|
||||
/* connection event mgmt */
|
||||
uint8_t reject_reason;
|
||||
uint8_t host_reply_opcode;
|
||||
uint8_t master_sca;
|
||||
uint8_t tx_win_size;
|
||||
uint8_t cur_ctrl_proc;
|
||||
uint8_t disconnect_reason;
|
||||
uint8_t rxd_disconnect_reason;
|
||||
uint8_t vers_nr;
|
||||
uint8_t conn_features;
|
||||
uint8_t remote_features[7];
|
||||
uint16_t pending_ctrl_procs;
|
||||
uint16_t event_cntr;
|
||||
uint16_t completed_pkts;
|
||||
uint16_t comp_id;
|
||||
uint16_t sub_vers_nr;
|
||||
uint16_t auth_pyld_tmo; /* could be ifdef'd. 10 msec units */
|
||||
|
||||
uint32_t access_addr;
|
||||
uint32_t crcinit; /* only low 24 bits used */
|
||||
/* XXX: do we need ce_end_time? Cant this be sched end time? */
|
||||
uint32_t ce_end_time; /* cputime at which connection event should end */
|
||||
uint32_t terminate_timeout;
|
||||
uint32_t last_scheduled;
|
||||
|
||||
/* Connection timing */
|
||||
uint16_t conn_itvl;
|
||||
uint16_t slave_latency;
|
||||
uint16_t supervision_tmo;
|
||||
uint16_t min_ce_len;
|
||||
uint16_t max_ce_len;
|
||||
uint16_t tx_win_off;
|
||||
uint32_t anchor_point;
|
||||
uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/
|
||||
uint8_t conn_itvl_usecs;
|
||||
uint32_t conn_itvl_ticks;
|
||||
uint32_t last_anchor_point; /* Slave only */
|
||||
uint32_t slave_cur_tx_win_usecs;
|
||||
uint32_t slave_cur_window_widening;
|
||||
uint32_t last_rxd_pdu_cputime; /* Used exclusively for supervision timer */
|
||||
|
||||
/*
|
||||
* Used to mark that identity address was used as InitA
|
||||
*/
|
||||
uint8_t inita_identity_used;
|
||||
|
||||
/* address information */
|
||||
uint8_t own_addr_type;
|
||||
uint8_t peer_addr_type;
|
||||
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
|
||||
|
||||
/*
|
||||
* XXX: TODO. Could save memory. Have single event at LL and put these
|
||||
* on a singly linked list. Only would need list pointer here.
|
||||
*/
|
||||
/* Connection end event */
|
||||
struct ble_npl_event conn_ev_end;
|
||||
|
||||
/* Packet transmit queue */
|
||||
struct os_mbuf *cur_tx_pdu;
|
||||
STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
|
||||
|
||||
/* List entry for active/free connection pools */
|
||||
union {
|
||||
SLIST_ENTRY(ble_ll_conn_sm) act_sle;
|
||||
STAILQ_ENTRY(ble_ll_conn_sm) free_stqe;
|
||||
};
|
||||
|
||||
/* LL control procedure response timer */
|
||||
struct ble_npl_callout ctrl_proc_rsp_timer;
|
||||
|
||||
/* For scheduling connections */
|
||||
struct ble_ll_sched_item conn_sch;
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
|
||||
struct ble_npl_callout auth_pyld_timer;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX: a note on all these structures for control procedures. First off,
|
||||
* all of these need to be ifdef'd to save memory. Another thing to
|
||||
* consider is this: since most control procedures can only run when no
|
||||
* others are running, can I use just one structure (a union)? Should I
|
||||
* allocate these from a pool? Not sure what to do. For now, I just use
|
||||
* a large chunk of memory per connection.
|
||||
*/
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
|
||||
struct ble_ll_conn_enc_data enc_data;
|
||||
#endif
|
||||
/*
|
||||
* For connection update procedure. XXX: can make this a pointer and
|
||||
* malloc it if we want to save space.
|
||||
*/
|
||||
struct hci_conn_update conn_param_req;
|
||||
|
||||
/* For connection update procedure */
|
||||
struct ble_ll_conn_upd_req conn_update_req;
|
||||
|
||||
/* XXX: for now, just store them all */
|
||||
struct ble_ll_conn_params conn_cp;
|
||||
|
||||
struct ble_ll_scan_sm *scansm;
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
|
||||
struct hci_ext_create_conn initial_params;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
|
||||
uint8_t sync_transfer_mode;
|
||||
uint16_t sync_transfer_skip;
|
||||
uint32_t sync_transfer_sync_timeout;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Flags */
|
||||
#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched)
|
||||
#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd)
|
||||
#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md)
|
||||
#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd)
|
||||
#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted)
|
||||
#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent)
|
||||
#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp)
|
||||
#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started)
|
||||
#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp)
|
||||
#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update)
|
||||
#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched)
|
||||
#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update)
|
||||
#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event)
|
||||
#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update)
|
||||
#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req)
|
||||
|
||||
/* Role */
|
||||
#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER)
|
||||
#define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE)
|
||||
|
||||
/*
|
||||
* Given a handle, returns an active connection state machine (or NULL if the
|
||||
* handle does not exist
|
||||
*
|
||||
*/
|
||||
struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
|
||||
|
||||
/* required for unit testing */
|
||||
uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency);
|
||||
|
||||
/* used to get anchor point for connection event specified */
|
||||
void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
|
||||
uint32_t *anchor, uint8_t *anchor_usecs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_LL_CONN_ */
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_CTRL_
|
||||
#define H_BLE_LL_CTRL_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* LL control procedures. This "enumeration" is not in the specification;
|
||||
* It is used to determine which LL control procedure is currently running
|
||||
* in a connection and which ones may be pending.
|
||||
*/
|
||||
#define BLE_LL_CTRL_PROC_CONN_UPDATE (0)
|
||||
#define BLE_LL_CTRL_PROC_CHAN_MAP_UPD (1)
|
||||
#define BLE_LL_CTRL_PROC_ENCRYPT (2)
|
||||
#define BLE_LL_CTRL_PROC_FEATURE_XCHG (3)
|
||||
#define BLE_LL_CTRL_PROC_VERSION_XCHG (4)
|
||||
#define BLE_LL_CTRL_PROC_TERMINATE (5)
|
||||
#define BLE_LL_CTRL_PROC_CONN_PARAM_REQ (6)
|
||||
#define BLE_LL_CTRL_PROC_LE_PING (7)
|
||||
#define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8)
|
||||
#define BLE_LL_CTRL_PROC_PHY_UPDATE (9)
|
||||
#define BLE_LL_CTRL_PROC_NUM (10)
|
||||
#define BLE_LL_CTRL_PROC_IDLE (255)
|
||||
|
||||
/* Checks if a particular control procedure is running */
|
||||
#define IS_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
|
||||
#define CLR_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs &= ~(1 << proc))
|
||||
|
||||
/* LL control procedure timeout */
|
||||
#define BLE_LL_CTRL_PROC_TIMEOUT_MS (40000) /* ms */
|
||||
|
||||
/*
|
||||
* LL CTRL PDU format
|
||||
* -> Opcode (1 byte)
|
||||
* -> Data (0 - 26 bytes)
|
||||
*/
|
||||
#define BLE_LL_CTRL_CONN_UPDATE_IND (0)
|
||||
#define BLE_LL_CTRL_CHANNEL_MAP_REQ (1)
|
||||
#define BLE_LL_CTRL_TERMINATE_IND (2)
|
||||
#define BLE_LL_CTRL_ENC_REQ (3)
|
||||
#define BLE_LL_CTRL_ENC_RSP (4)
|
||||
#define BLE_LL_CTRL_START_ENC_REQ (5)
|
||||
#define BLE_LL_CTRL_START_ENC_RSP (6)
|
||||
#define BLE_LL_CTRL_UNKNOWN_RSP (7)
|
||||
#define BLE_LL_CTRL_FEATURE_REQ (8)
|
||||
#define BLE_LL_CTRL_FEATURE_RSP (9)
|
||||
#define BLE_LL_CTRL_PAUSE_ENC_REQ (10)
|
||||
#define BLE_LL_CTRL_PAUSE_ENC_RSP (11)
|
||||
#define BLE_LL_CTRL_VERSION_IND (12)
|
||||
#define BLE_LL_CTRL_REJECT_IND (13)
|
||||
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (14)
|
||||
#define BLE_LL_CTRL_CONN_PARM_REQ (15)
|
||||
#define BLE_LL_CTRL_CONN_PARM_RSP (16)
|
||||
#define BLE_LL_CTRL_REJECT_IND_EXT (17)
|
||||
#define BLE_LL_CTRL_PING_REQ (18)
|
||||
#define BLE_LL_CTRL_PING_RSP (19)
|
||||
#define BLE_LL_CTRL_LENGTH_REQ (20)
|
||||
#define BLE_LL_CTRL_LENGTH_RSP (21)
|
||||
#define BLE_LL_CTRL_PHY_REQ (22)
|
||||
#define BLE_LL_CTRL_PHY_RSP (23)
|
||||
#define BLE_LL_CTRL_PHY_UPDATE_IND (24)
|
||||
#define BLE_LL_CTRL_MIN_USED_CHAN_IND (25)
|
||||
#define BLE_LL_CTRL_CTE_REQ (26)
|
||||
#define BLE_LL_CTRL_CTE_RSP (27)
|
||||
#define BLE_LL_CTRL_PERIODIC_SYNC_IND (28)
|
||||
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (29)
|
||||
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (30)
|
||||
|
||||
/* Maximum opcode value */
|
||||
#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CLOCK_ACCURACY_RSP + 1)
|
||||
|
||||
extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
|
||||
|
||||
/* Maximum LL control PDU size */
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
|
||||
#define BLE_LL_CTRL_MAX_PDU_LEN (35)
|
||||
#else
|
||||
#define BLE_LL_CTRL_MAX_PDU_LEN (27)
|
||||
#endif
|
||||
|
||||
/* LL control connection update request */
|
||||
struct ble_ll_conn_upd_req
|
||||
{
|
||||
uint8_t winsize;
|
||||
uint16_t winoffset;
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint16_t instant;
|
||||
};
|
||||
#define BLE_LL_CTRL_CONN_UPD_REQ_LEN (11)
|
||||
|
||||
/* LL control channel map request */
|
||||
struct ble_ll_chan_map_req
|
||||
{
|
||||
uint8_t chmap[5];
|
||||
uint16_t instant;
|
||||
};
|
||||
#define BLE_LL_CTRL_CHAN_MAP_LEN (7)
|
||||
|
||||
/*
|
||||
* LL control terminate ind
|
||||
* -> error code (1 byte)
|
||||
*/
|
||||
#define BLE_LL_CTRL_TERMINATE_IND_LEN (1)
|
||||
|
||||
/* LL control enc req */
|
||||
struct ble_ll_enc_req
|
||||
{
|
||||
uint8_t rand[8];
|
||||
uint16_t ediv;
|
||||
uint8_t skdm[8];
|
||||
uint32_t ivm;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_ENC_REQ_LEN (22)
|
||||
|
||||
/* LL control enc rsp */
|
||||
struct ble_ll_enc_rsp
|
||||
{
|
||||
uint8_t skds[8];
|
||||
uint32_t ivs;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_ENC_RSP_LEN (12)
|
||||
|
||||
/* LL control start/pause enc request and response */
|
||||
#define BLE_LL_CTRL_START_ENC_REQ_LEN (0)
|
||||
#define BLE_LL_CTRL_START_ENC_RSP_LEN (0)
|
||||
#define BLE_LL_CTRL_PAUSE_ENC_REQ_LEN (0)
|
||||
#define BLE_LL_CTRL_PAUSE_ENC_RSP_LEN (0)
|
||||
|
||||
/*
|
||||
* LL control unknown response
|
||||
* -> 1 byte which contains the unknown or un-supported opcode.
|
||||
*/
|
||||
#define BLE_LL_CTRL_UNK_RSP_LEN (1)
|
||||
|
||||
/*
|
||||
* LL control feature req and LL control feature rsp
|
||||
* -> 8 bytes of data containing features supported by device.
|
||||
*/
|
||||
#define BLE_LL_CTRL_FEATURE_LEN (8)
|
||||
|
||||
/*
|
||||
* LL control version ind
|
||||
* -> version (1 byte):
|
||||
* Contains the version number of the bluetooth controller specification.
|
||||
* -> comp_id (2 bytes)
|
||||
* Contains the company identifier of the manufacturer of the controller.
|
||||
* -> sub_ver_num: Contains a unique value for implementation or revision of
|
||||
* the bluetooth controller.
|
||||
*/
|
||||
struct ble_ll_version_ind
|
||||
{
|
||||
uint8_t ble_ctrlr_ver;
|
||||
uint16_t company_id;
|
||||
uint16_t sub_ver_num;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_VERSION_IND_LEN (5)
|
||||
|
||||
/*
|
||||
* LL control reject ind
|
||||
* -> error code (1 byte): contains reason why request was rejected.
|
||||
*/
|
||||
#define BLE_LL_CTRL_REJ_IND_LEN (1)
|
||||
|
||||
/*
|
||||
* LL control slave feature req
|
||||
* -> 8 bytes of data containing features supported by device.
|
||||
*/
|
||||
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN (8)
|
||||
|
||||
/* LL control connection param req and connection param rsp */
|
||||
struct ble_ll_conn_params
|
||||
{
|
||||
uint16_t interval_min;
|
||||
uint16_t interval_max;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
uint8_t pref_periodicity;
|
||||
uint16_t ref_conn_event_cnt;
|
||||
uint16_t offset0;
|
||||
uint16_t offset1;
|
||||
uint16_t offset2;
|
||||
uint16_t offset3;
|
||||
uint16_t offset4;
|
||||
uint16_t offset5;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_CONN_PARAMS_LEN (23)
|
||||
|
||||
/* LL control reject ind ext */
|
||||
struct ble_ll_reject_ind_ext
|
||||
{
|
||||
uint8_t reject_opcode;
|
||||
uint8_t err_code;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_REJECT_IND_EXT_LEN (2)
|
||||
|
||||
/* LL control ping req and ping rsp (contain no data) */
|
||||
#define BLE_LL_CTRL_PING_LEN (0)
|
||||
|
||||
/*
|
||||
* LL control length req and length rsp
|
||||
* -> max_rx_bytes (2 bytes): defines connMaxRxOctets. Range 27 to 251
|
||||
* -> max_rx_time (2 bytes): defines connMaxRxTime. Range 328 to 2120 usecs.
|
||||
* -> max_tx_bytes (2 bytes): defines connMaxTxOctets. Range 27 to 251
|
||||
* -> max_tx_time (2 bytes): defines connMaxTxTime. Range 328 to 2120 usecs.
|
||||
*/
|
||||
struct ble_ll_len_req
|
||||
{
|
||||
uint16_t max_rx_bytes;
|
||||
uint16_t max_rx_time;
|
||||
uint16_t max_tx_bytes;
|
||||
uint16_t max_tx_time;
|
||||
};
|
||||
|
||||
#define BLE_LL_CTRL_LENGTH_REQ_LEN (8)
|
||||
|
||||
/* PHY request/response */
|
||||
#define BLE_LL_CTRL_PHY_REQ_LEN (2)
|
||||
#define BLE_LL_CTRL_PHY_RSP_LEN (2)
|
||||
#define BLE_LL_CTRL_PHY_UPD_IND_LEN (4)
|
||||
|
||||
/* Min used channels */
|
||||
#define BLE_LL_CTRL_MIN_USED_CHAN_LEN (2)
|
||||
|
||||
/* CTE REQ */
|
||||
#define BLE_LL_CTRL_CTE_REQ_LEN (1)
|
||||
|
||||
/* CTE RSP (contains no data) */
|
||||
#define BLE_LL_CTRL_CTE_RSP_LEN (0)
|
||||
|
||||
/* Periodic Sync Transfer IND */
|
||||
#define BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN (34)
|
||||
|
||||
/* Clock accuracy request/response */
|
||||
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN (1)
|
||||
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN (1)
|
||||
|
||||
/* API */
|
||||
struct ble_ll_conn_sm;
|
||||
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
|
||||
void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc);
|
||||
int ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om);
|
||||
void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm);
|
||||
int ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode);
|
||||
uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm,
|
||||
uint8_t *rsp,
|
||||
struct ble_ll_conn_params *req);
|
||||
int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm,
|
||||
uint8_t rej_opcode, uint8_t err);
|
||||
int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm);
|
||||
int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu);
|
||||
int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr);
|
||||
int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm);
|
||||
int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu);
|
||||
|
||||
void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
|
||||
struct ble_ll_conn_params *cp);
|
||||
void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status);
|
||||
void ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm,
|
||||
uint8_t status);
|
||||
void ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status);
|
||||
void ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status);
|
||||
int ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm);
|
||||
int ble_ll_hci_ev_hw_err(uint8_t hw_err);
|
||||
void ble_ll_hci_ev_databuf_overflow(void);
|
||||
void ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
|
||||
uint8_t peer_addr_type);
|
||||
void ble_ll_hci_ev_send_scan_timeout(void);
|
||||
void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
|
||||
uint16_t conn_handle, uint8_t events);
|
||||
int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status);
|
||||
void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm);
|
||||
void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line);
|
||||
|
||||
uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
|
||||
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_LL_CTRL_ */
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_LL_HCI_
|
||||
#define H_BLE_LL_HCI_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nimble/nimble/include/nimble/hci_common.h"
|
||||
|
||||
/* For supported commands */
|
||||
#define BLE_LL_SUPP_CMD_LEN (42)
|
||||
extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN];
|
||||
|
||||
/* The largest event the controller will send. */
|
||||
#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)
|
||||
|
||||
/*
|
||||
* This determines the number of outstanding commands allowed from the
|
||||
* host to the controller. NOTE: you cannot change this without modifying
|
||||
* other portions of the code as we currently use a global os event for
|
||||
* the command; you would need to allocate a pool of these.
|
||||
*/
|
||||
#define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1)
|
||||
|
||||
typedef void (*ble_ll_hci_post_cmd_complete_cb)(void);
|
||||
|
||||
/* Initialize LL HCI */
|
||||
void ble_ll_hci_init(void);
|
||||
|
||||
/* Used to determine if the LE event is enabled/disabled */
|
||||
bool ble_ll_hci_is_le_event_enabled(unsigned int subev);
|
||||
|
||||
/* Used to determine if event is enabled/disabled */
|
||||
bool ble_ll_hci_is_event_enabled(unsigned int evcode);
|
||||
|
||||
/* Send event from controller to host */
|
||||
int ble_ll_hci_event_send(struct ble_hci_ev *hci_ev);
|
||||
|
||||
/* Sends a command complete with a no-op opcode to host */
|
||||
void ble_ll_hci_send_noop(void);
|
||||
|
||||
/* Checks the preferref phy masks from set default phy and set phy commands */
|
||||
int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys,
|
||||
uint8_t *txphy, uint8_t *rxphy);
|
||||
|
||||
/* Returns true if Extended Advertising HCI commands are in use */
|
||||
bool ble_ll_hci_adv_mode_ext(void);
|
||||
|
||||
/* Get TX power compensation rounded to integer dB */
|
||||
int8_t ble_ll_get_tx_pwr_compensation(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* H_BLE_LL_HCI_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user