Bluetooth: Implemented new DIS characteristics
Implemented new DIS characteristics: - UDI for medical devices - IEEE 11073-20601 Regulatory Certification Data List - System ID Also fixed buffer overflow bug when assigning too long DIS string literals Signed-off-by: Simen Eilevstjønn <simen.eilevstjonn@laerdal.com>
This commit is contained in:
parent
eb406f80bc
commit
2c64fe7f37
3 changed files with 367 additions and 71 deletions
|
@ -5090,6 +5090,16 @@ struct bt_uuid_128 {
|
||||||
#define BT_UUID_GATT_SL \
|
#define BT_UUID_GATT_SL \
|
||||||
BT_UUID_DECLARE_16(BT_UUID_GATT_SL_VAL)
|
BT_UUID_DECLARE_16(BT_UUID_GATT_SL_VAL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GATT Characteristic UDI for Medical Devices UUID Value
|
||||||
|
*/
|
||||||
|
#define BT_UUID_UDI_FOR_MEDICAL_DEVICES_VAL 0x2bff
|
||||||
|
/**
|
||||||
|
* @brief GATT Characteristic UDI for Medical Devices
|
||||||
|
*/
|
||||||
|
#define BT_UUID_UDI_FOR_MEDICAL_DEVICES \
|
||||||
|
BT_UUID_DECLARE_16(BT_UUID_UDI_FOR_MEDICAL_DEVICES_VAL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gaming Service UUID value
|
* @brief Gaming Service UUID value
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -144,4 +144,74 @@ config BT_DIS_SW_REV_STR
|
||||||
help
|
help
|
||||||
Enable software revision characteristic in Device Information Service.
|
Enable software revision characteristic in Device Information Service.
|
||||||
|
|
||||||
|
config BT_DIS_UDI
|
||||||
|
bool "DIS UDI for Medical Devices characteristic"
|
||||||
|
help
|
||||||
|
Enable UDI for Medical Devices characteristic in Device Information Service.
|
||||||
|
|
||||||
|
if BT_DIS_UDI
|
||||||
|
config BT_DIS_UDI_LABEL_STR
|
||||||
|
string "UDI Label"
|
||||||
|
help
|
||||||
|
String value matching the UDI in human readable form
|
||||||
|
as assigned to the product by a recognized UDI Issuer.
|
||||||
|
|
||||||
|
config BT_DIS_UDI_DI_STR
|
||||||
|
string "UDI Device Identifier"
|
||||||
|
help
|
||||||
|
A fixed portion of a UDI that identifies the labeler and the
|
||||||
|
specific version or model of a device.
|
||||||
|
|
||||||
|
config BT_DIS_UDI_ISSUER_STR
|
||||||
|
string "UDI Issuer"
|
||||||
|
help
|
||||||
|
OID representing the UDI Issuing Organization, such as GS1.
|
||||||
|
|
||||||
|
config BT_DIS_UDI_AUTHORITY_STR
|
||||||
|
string "UDI Authority"
|
||||||
|
help
|
||||||
|
OID representing the regional UDI Authority, such as the US FDA.
|
||||||
|
endif # BT_DIS_UDI
|
||||||
|
|
||||||
|
config BT_DIS_SYSTEM_ID
|
||||||
|
bool "DIS System ID characteristic [experimental]"
|
||||||
|
select EXPERIMENTAL
|
||||||
|
help
|
||||||
|
Enable System ID characteristic in Device Information Service.
|
||||||
|
The System ID characteristic is used to represent an extended unique identifier (EUI) of the system
|
||||||
|
implementing the service that contains this characteristic. This 64-bit structure is an EUI-64 which consists
|
||||||
|
of an Organizationally Unique Identifier (OUI) concatenated with a manufacturer-defined identifier.
|
||||||
|
|
||||||
|
This will be transmitted as the 40 bit identifier followed by the 24-bit OUI.
|
||||||
|
Both in little-endian format.
|
||||||
|
|
||||||
|
if BT_DIS_SYSTEM_ID
|
||||||
|
config BT_DIS_SYSTEM_ID_OUI
|
||||||
|
hex "Organizationally Unique Identifier (OUI) of the manufacturer."
|
||||||
|
range 0 0xFFFFFF
|
||||||
|
default 0
|
||||||
|
help
|
||||||
|
The OUI is a 24-bit number issued by the IEEE Registration Authority.
|
||||||
|
System ID characteristic in Device Information Service.
|
||||||
|
Shall contain an Organisationally Unique Identifier (OUI) followed by a manufacturer-defined indentifier unique for the device.
|
||||||
|
|
||||||
|
config BT_DIS_SYSTEM_ID_IDENTIFIER
|
||||||
|
hex "Manufacturer-defined unique identifier."
|
||||||
|
range 0 0xFFFFFFFFFF
|
||||||
|
default 0
|
||||||
|
help
|
||||||
|
The manufacturer-defined unique identifier is 40 bits long.
|
||||||
|
endif # BT_DIS_SYSTEM_ID
|
||||||
|
|
||||||
|
config BT_DIS_IEEE_RCDL
|
||||||
|
bool "DIS IEEE 11073-20601 Regulatory Certification Data List characteristic"
|
||||||
|
help
|
||||||
|
Enable IEEE 11073-20601 Regulatory Certification Data List characteristic in Device Information Service.
|
||||||
|
|
||||||
|
config BT_DIS_IEEE_RCDL_STR
|
||||||
|
string "IEEE 11073-20601 Regulatory Certification Data List"
|
||||||
|
depends on BT_DIS_IEEE_RCDL
|
||||||
|
help
|
||||||
|
IEEE 11073-20601 Regulatory Certification Data List characteristic in Device Information Service string contents.
|
||||||
|
|
||||||
endif # BT_DIS
|
endif # BT_DIS
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include <zephyr/bluetooth/uuid.h>
|
#include <zephyr/bluetooth/uuid.h>
|
||||||
#include <zephyr/bluetooth/gatt.h>
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/bluetooth/byteorder.h>
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_SERVICE_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_SERVICE_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(bt_dis);
|
LOG_MODULE_REGISTER(bt_dis);
|
||||||
|
@ -45,105 +48,262 @@ static struct dis_pnp dis_pnp_id = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_DIS_SETTINGS)
|
#if defined(CONFIG_BT_DIS_SYSTEM_ID)
|
||||||
static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX] = CONFIG_BT_DIS_MODEL;
|
/*
|
||||||
static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX] = CONFIG_BT_DIS_MANUF;
|
* Casting to uint64_t since the value is at most 5 bytes, but will appear as a 32-bit literal if it
|
||||||
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
* is less, giving a warning when right-shifting by 32.
|
||||||
static uint8_t dis_serial_number[CONFIG_BT_DIS_STR_MAX] =
|
*/
|
||||||
CONFIG_BT_DIS_SERIAL_NUMBER_STR;
|
static uint8_t dis_system_id[8] = {BT_BYTES_LIST_LE40((uint64_t)CONFIG_BT_DIS_SYSTEM_ID_IDENTIFIER),
|
||||||
#endif
|
BT_BYTES_LIST_LE24(CONFIG_BT_DIS_SYSTEM_ID_OUI)};
|
||||||
#if defined(CONFIG_BT_DIS_FW_REV)
|
|
||||||
static uint8_t dis_fw_rev[CONFIG_BT_DIS_STR_MAX] =
|
|
||||||
CONFIG_BT_DIS_FW_REV_STR;
|
|
||||||
#endif
|
|
||||||
#if defined(CONFIG_BT_DIS_HW_REV)
|
|
||||||
static uint8_t dis_hw_rev[CONFIG_BT_DIS_STR_MAX] =
|
|
||||||
CONFIG_BT_DIS_HW_REV_STR;
|
|
||||||
#endif
|
|
||||||
#if defined(CONFIG_BT_DIS_SW_REV)
|
|
||||||
static uint8_t dis_sw_rev[CONFIG_BT_DIS_STR_MAX] =
|
|
||||||
CONFIG_BT_DIS_SW_REV_STR;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BT_DIS_MODEL_REF dis_model
|
#if defined(CONFIG_BT_DIS_SETTINGS)
|
||||||
#define BT_DIS_MANUF_REF dis_manuf
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MODEL) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
#define BT_DIS_SERIAL_NUMBER_STR_REF dis_serial_number
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
#define BT_DIS_FW_REV_STR_REF dis_fw_rev
|
static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MODEL;
|
||||||
#define BT_DIS_HW_REV_STR_REF dis_hw_rev
|
static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MANUF;
|
||||||
#define BT_DIS_SW_REV_STR_REF dis_sw_rev
|
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_SERIAL_NUMBER_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
static uint8_t dis_serial_number[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_SERIAL_NUMBER_STR;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_FW_REV)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_FW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
static uint8_t dis_fw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_FW_REV_STR;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_HW_REV)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_HW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
static uint8_t dis_hw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_HW_REV_STR;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_SW_REV)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_SW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
static uint8_t dis_sw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_SW_REV_STR;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_UDI)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_LABEL_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_DI_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_ISSUER_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_AUTHORITY_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
|
||||||
|
static uint8_t dis_udi_label[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_LABEL_STR;
|
||||||
|
static uint8_t dis_udi_di[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_DI_STR;
|
||||||
|
static uint8_t dis_udi_issuer[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_ISSUER_STR;
|
||||||
|
static uint8_t dis_udi_authority[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_AUTHORITY_STR;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_IEEE_RCDL)
|
||||||
|
BUILD_ASSERT(sizeof(CONFIG_BT_DIS_IEEE_RCDL_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
|
||||||
|
static uint8_t dis_ieee_rcdl[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_IEEE_RCDL_STR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BT_DIS_MODEL_REF dis_model
|
||||||
|
#define BT_DIS_MANUF_REF dis_manuf
|
||||||
|
#define BT_DIS_SERIAL_NUMBER_STR_REF dis_serial_number
|
||||||
|
#define BT_DIS_FW_REV_STR_REF dis_fw_rev
|
||||||
|
#define BT_DIS_HW_REV_STR_REF dis_hw_rev
|
||||||
|
#define BT_DIS_SW_REV_STR_REF dis_sw_rev
|
||||||
|
#define BT_DIS_UDI_LABEL_STR_REF dis_udi_label
|
||||||
|
#define BT_DIS_UDI_DI_STR_REF dis_udi_di
|
||||||
|
#define BT_DIS_UDI_ISSUER_STR_REF dis_udi_issuer
|
||||||
|
#define BT_DIS_UDI_AUTHORITY_STR_REF dis_udi_authority
|
||||||
|
#define BT_DIS_IEEE_RCDL_STR_REF dis_ieee_rcdl
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When assigning too long string literals to the arrays,
|
||||||
|
* the literals may be truncated, removing the null terminator.
|
||||||
|
* Using strnlen to avoid sending data outside the array.
|
||||||
|
*/
|
||||||
|
|
||||||
#else /* CONFIG_BT_DIS_SETTINGS */
|
#else /* CONFIG_BT_DIS_SETTINGS */
|
||||||
|
|
||||||
#define BT_DIS_MODEL_REF CONFIG_BT_DIS_MODEL
|
#define BT_DIS_MODEL_REF CONFIG_BT_DIS_MODEL
|
||||||
#define BT_DIS_MANUF_REF CONFIG_BT_DIS_MANUF
|
#define BT_DIS_MANUF_REF CONFIG_BT_DIS_MANUF
|
||||||
#define BT_DIS_SERIAL_NUMBER_STR_REF CONFIG_BT_DIS_SERIAL_NUMBER_STR
|
#define BT_DIS_SERIAL_NUMBER_STR_REF CONFIG_BT_DIS_SERIAL_NUMBER_STR
|
||||||
#define BT_DIS_FW_REV_STR_REF CONFIG_BT_DIS_FW_REV_STR
|
#define BT_DIS_FW_REV_STR_REF CONFIG_BT_DIS_FW_REV_STR
|
||||||
#define BT_DIS_HW_REV_STR_REF CONFIG_BT_DIS_HW_REV_STR
|
#define BT_DIS_HW_REV_STR_REF CONFIG_BT_DIS_HW_REV_STR
|
||||||
#define BT_DIS_SW_REV_STR_REF CONFIG_BT_DIS_SW_REV_STR
|
#define BT_DIS_SW_REV_STR_REF CONFIG_BT_DIS_SW_REV_STR
|
||||||
|
#define BT_DIS_UDI_LABEL_STR_REF CONFIG_BT_DIS_UDI_LABEL_STR
|
||||||
|
#define BT_DIS_UDI_DI_STR_REF CONFIG_BT_DIS_UDI_DI_STR
|
||||||
|
#define BT_DIS_UDI_ISSUER_STR_REF CONFIG_BT_DIS_UDI_ISSUER_STR
|
||||||
|
#define BT_DIS_UDI_AUTHORITY_STR_REF CONFIG_BT_DIS_UDI_AUTHORITY_STR
|
||||||
|
#define BT_DIS_IEEE_RCDL_STR_REF CONFIG_BT_DIS_IEEE_RCDL_STR
|
||||||
|
|
||||||
#endif /* CONFIG_BT_DIS_SETTINGS */
|
#endif /* CONFIG_BT_DIS_SETTINGS */
|
||||||
|
|
||||||
static ssize_t read_str(struct bt_conn *conn,
|
static ssize_t read_str(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||||
const struct bt_gatt_attr *attr, void *buf,
|
uint16_t len, uint16_t offset)
|
||||||
uint16_t len, uint16_t offset)
|
|
||||||
{
|
{
|
||||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
|
||||||
strlen(attr->user_data));
|
strlen(attr->user_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_BT_DIS_PNP
|
#if CONFIG_BT_DIS_PNP
|
||||||
static ssize_t read_pnp_id(struct bt_conn *conn,
|
static ssize_t read_pnp_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||||
const struct bt_gatt_attr *attr, void *buf,
|
|
||||||
uint16_t len, uint16_t offset)
|
uint16_t len, uint16_t offset)
|
||||||
{
|
{
|
||||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &dis_pnp_id,
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &dis_pnp_id, sizeof(dis_pnp_id));
|
||||||
sizeof(dis_pnp_id));
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_BT_DIS_SYSTEM_ID
|
||||||
|
static ssize_t read_system_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||||
|
uint16_t len, uint16_t offset)
|
||||||
|
{
|
||||||
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, dis_system_id,
|
||||||
|
sizeof(dis_system_id));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_BT_DIS_UDI
|
||||||
|
#define DIS_STR_SIZE(x) ((x[0]) != '\0' ? strlen(x) + sizeof('\0') : 0)
|
||||||
|
#define BT_DIS_UDI_FLAG_LABEL (!!BT_DIS_UDI_LABEL_STR_REF[0])
|
||||||
|
#define BT_DIS_UDI_FLAG_DI (!!BT_DIS_UDI_DI_STR_REF[0])
|
||||||
|
#define BT_DIS_UDI_FLAG_ISSUER (!!BT_DIS_UDI_ISSUER_STR_REF[0])
|
||||||
|
#define BT_DIS_UDI_FLAG_AUTHORITY (!!BT_DIS_UDI_AUTHORITY_STR_REF[0])
|
||||||
|
#define BT_DIS_UDI_FLAGS \
|
||||||
|
(BT_DIS_UDI_FLAG_LABEL | (BT_DIS_UDI_FLAG_DI << 1) | (BT_DIS_UDI_FLAG_ISSUER << 2) | \
|
||||||
|
(BT_DIS_UDI_FLAG_AUTHORITY << 3))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UDI for medical devices contains a flag and 4 different null-terminated strings that may have
|
||||||
|
* unknown length. This requires its own encode method.
|
||||||
|
*/
|
||||||
|
static void read_udi_subval(const char *str, uint16_t val_len, char *buf, uint16_t *bytes_read,
|
||||||
|
uint16_t *index, uint16_t len, uint16_t offset)
|
||||||
|
{
|
||||||
|
/* String should not be with included null-terminator if empty */
|
||||||
|
if (val_len == sizeof('\0')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*bytes_read == len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*index + val_len < offset) {
|
||||||
|
*index += val_len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < val_len; i++) {
|
||||||
|
if (*index >= offset && *bytes_read < len) {
|
||||||
|
buf[*bytes_read] = str[i];
|
||||||
|
|
||||||
|
(*bytes_read)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*index)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t read_udi(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||||
|
uint16_t len, uint16_t offset)
|
||||||
|
{
|
||||||
|
uint16_t bytes_read = 0;
|
||||||
|
|
||||||
|
char *buf_i = (char *)buf;
|
||||||
|
|
||||||
|
/* Flag */
|
||||||
|
uint16_t index = sizeof(uint8_t);
|
||||||
|
|
||||||
|
if (offset == 0) {
|
||||||
|
buf_i[0] = BT_DIS_UDI_FLAGS;
|
||||||
|
bytes_read = 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_udi_subval(BT_DIS_UDI_LABEL_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_LABEL_STR_REF), buf_i,
|
||||||
|
&bytes_read, &index, len, offset);
|
||||||
|
read_udi_subval(BT_DIS_UDI_DI_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_DI_STR_REF), buf_i,
|
||||||
|
&bytes_read, &index, len, offset);
|
||||||
|
read_udi_subval(BT_DIS_UDI_ISSUER_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_ISSUER_STR_REF), buf_i,
|
||||||
|
&bytes_read, &index, len, offset);
|
||||||
|
read_udi_subval(BT_DIS_UDI_AUTHORITY_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_AUTHORITY_STR_REF),
|
||||||
|
buf_i, &bytes_read, &index, len, offset);
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Device Information Service Declaration */
|
/* Device Information Service Declaration */
|
||||||
BT_GATT_SERVICE_DEFINE(dis_svc,
|
BT_GATT_SERVICE_DEFINE(
|
||||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS),
|
dis_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS),
|
||||||
|
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_str, NULL, BT_DIS_MODEL_REF),
|
read_str, NULL, BT_DIS_MODEL_REF),
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MANUFACTURER_NAME,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MANUFACTURER_NAME, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_str, NULL, BT_DIS_MANUF_REF),
|
read_str, NULL, BT_DIS_MANUF_REF),
|
||||||
#if CONFIG_BT_DIS_PNP
|
#if CONFIG_BT_DIS_PNP
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_PNP_ID,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_PNP_ID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_pnp_id, NULL, &dis_pnp_id),
|
read_pnp_id, NULL, &dis_pnp_id),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SERIAL_NUMBER,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SERIAL_NUMBER, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
read_str, NULL, BT_DIS_SERIAL_NUMBER_STR_REF),
|
||||||
read_str, NULL,
|
|
||||||
BT_DIS_SERIAL_NUMBER_STR_REF),
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_BT_DIS_FW_REV)
|
#if defined(CONFIG_BT_DIS_FW_REV)
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_FIRMWARE_REVISION,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_FIRMWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_str, NULL, BT_DIS_FW_REV_STR_REF),
|
read_str, NULL, BT_DIS_FW_REV_STR_REF),
|
||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_BT_DIS_HW_REV)
|
#if defined(CONFIG_BT_DIS_HW_REV)
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_HARDWARE_REVISION,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_HARDWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_str, NULL, BT_DIS_HW_REV_STR_REF),
|
read_str, NULL, BT_DIS_HW_REV_STR_REF),
|
||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_BT_DIS_SW_REV)
|
#if defined(CONFIG_BT_DIS_SW_REV)
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SOFTWARE_REVISION,
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SOFTWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
|
||||||
read_str, NULL, BT_DIS_SW_REV_STR_REF),
|
read_str, NULL, BT_DIS_SW_REV_STR_REF),
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_UDI)
|
||||||
|
BT_GATT_CHARACTERISTIC(BT_UUID_UDI_FOR_MEDICAL_DEVICES, BT_GATT_CHRC_READ,
|
||||||
|
BT_GATT_PERM_READ, read_udi, NULL, NULL),
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_SYSTEM_ID)
|
||||||
|
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SYSTEM_ID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
|
read_system_id, NULL, NULL),
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_IEEE_RCDL)
|
||||||
|
BT_GATT_CHARACTERISTIC(BT_UUID_GATT_IEEE_RCDL, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
|
read_str, NULL, BT_DIS_IEEE_RCDL_STR_REF),
|
||||||
|
#endif
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#if defined(CONFIG_BT_DIS_SETTINGS)
|
#if defined(CONFIG_BT_DIS_SETTINGS)
|
||||||
static int dis_set(const char *name, size_t len_rd,
|
#if defined(CONFIG_BT_DIS_UDI)
|
||||||
settings_read_cb read_cb, void *store)
|
static void dis_update_udi_value(const char *new, char *old, settings_read_cb read_cb,
|
||||||
|
const char *logkey)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The characteristic contains 1 one-byte flag and 4-null-terminated.
|
||||||
|
* The null-terminators are only present for strings that are in the flags.
|
||||||
|
*/
|
||||||
|
const size_t merged_size = sizeof(uint8_t) + DIS_STR_SIZE(BT_DIS_UDI_LABEL_STR_REF) +
|
||||||
|
DIS_STR_SIZE(BT_DIS_UDI_DI_STR_REF) +
|
||||||
|
DIS_STR_SIZE(BT_DIS_UDI_ISSUER_STR_REF) +
|
||||||
|
DIS_STR_SIZE(BT_DIS_UDI_AUTHORITY_STR_REF);
|
||||||
|
|
||||||
|
size_t without_old = merged_size - DIS_STR_SIZE(old);
|
||||||
|
|
||||||
|
bool valid = BT_ATT_MAX_ATTRIBUTE_LEN >= without_old + DIS_STR_SIZE(new);
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
LOG_ERR("Failed to set UDI %s. Not enough space. The sum of the 4 DIS UDI for "
|
||||||
|
"Medical Devices strings may not exceed the maximum attribute length.",
|
||||||
|
logkey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t len = read_cb((void *)new, (void *)old, CONFIG_BT_DIS_STR_MAX);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
LOG_ERR("Failed to read UDI %s from storage (err %zd)", logkey, len);
|
||||||
|
} else {
|
||||||
|
old[len] = '\0';
|
||||||
|
|
||||||
|
LOG_DBG("UDI %s set to %s", logkey, old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int dis_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *store)
|
||||||
{
|
{
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
int nlen;
|
int nlen;
|
||||||
|
@ -153,8 +313,7 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
if (!strncmp(name, "manuf", nlen)) {
|
if (!strncmp(name, "manuf", nlen)) {
|
||||||
len = read_cb(store, &dis_manuf, sizeof(dis_manuf) - 1);
|
len = read_cb(store, &dis_manuf, sizeof(dis_manuf) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read manufacturer from storage"
|
LOG_ERR("Failed to read manufacturer from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_manuf[len] = '\0';
|
dis_manuf[len] = '\0';
|
||||||
|
|
||||||
|
@ -165,8 +324,7 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
if (!strncmp(name, "model", nlen)) {
|
if (!strncmp(name, "model", nlen)) {
|
||||||
len = read_cb(store, &dis_model, sizeof(dis_model) - 1);
|
len = read_cb(store, &dis_model, sizeof(dis_model) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read model from storage"
|
LOG_ERR("Failed to read model from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_model[len] = '\0';
|
dis_model[len] = '\0';
|
||||||
|
|
||||||
|
@ -176,11 +334,9 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
}
|
}
|
||||||
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
#if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
|
||||||
if (!strncmp(name, "serial", nlen)) {
|
if (!strncmp(name, "serial", nlen)) {
|
||||||
len = read_cb(store, &dis_serial_number,
|
len = read_cb(store, &dis_serial_number, sizeof(dis_serial_number) - 1);
|
||||||
sizeof(dis_serial_number) - 1);
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read serial number from storage"
|
LOG_ERR("Failed to read serial number from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_serial_number[len] = '\0';
|
dis_serial_number[len] = '\0';
|
||||||
|
|
||||||
|
@ -193,8 +349,7 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
if (!strncmp(name, "fw", nlen)) {
|
if (!strncmp(name, "fw", nlen)) {
|
||||||
len = read_cb(store, &dis_fw_rev, sizeof(dis_fw_rev) - 1);
|
len = read_cb(store, &dis_fw_rev, sizeof(dis_fw_rev) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read firmware revision from storage"
|
LOG_ERR("Failed to read firmware revision from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_fw_rev[len] = '\0';
|
dis_fw_rev[len] = '\0';
|
||||||
|
|
||||||
|
@ -207,8 +362,7 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
if (!strncmp(name, "hw", nlen)) {
|
if (!strncmp(name, "hw", nlen)) {
|
||||||
len = read_cb(store, &dis_hw_rev, sizeof(dis_hw_rev) - 1);
|
len = read_cb(store, &dis_hw_rev, sizeof(dis_hw_rev) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read hardware revision from storage"
|
LOG_ERR("Failed to read hardware revision from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_hw_rev[len] = '\0';
|
dis_hw_rev[len] = '\0';
|
||||||
|
|
||||||
|
@ -221,8 +375,7 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
if (!strncmp(name, "sw", nlen)) {
|
if (!strncmp(name, "sw", nlen)) {
|
||||||
len = read_cb(store, &dis_sw_rev, sizeof(dis_sw_rev) - 1);
|
len = read_cb(store, &dis_sw_rev, sizeof(dis_sw_rev) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
LOG_ERR("Failed to read software revision from storage"
|
LOG_ERR("Failed to read software revision from storage (err %zd)", len);
|
||||||
" (err %zd)", len);
|
|
||||||
} else {
|
} else {
|
||||||
dis_sw_rev[len] = '\0';
|
dis_sw_rev[len] = '\0';
|
||||||
|
|
||||||
|
@ -230,6 +383,69 @@ static int dis_set(const char *name, size_t len_rd,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_UDI)
|
||||||
|
if (!strncmp(name, "udi_label", nlen)) {
|
||||||
|
dis_update_udi_value(store, BT_DIS_UDI_LABEL_STR_REF, read_cb, "label");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(name, "udi_di", nlen)) {
|
||||||
|
dis_update_udi_value(store, BT_DIS_UDI_DI_STR_REF, read_cb, "device information");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(name, "udi_issuer", nlen)) {
|
||||||
|
dis_update_udi_value(store, BT_DIS_UDI_ISSUER_STR_REF, read_cb, "issuer");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(name, "udi_authority", nlen)) {
|
||||||
|
dis_update_udi_value(store, BT_DIS_UDI_AUTHORITY_STR_REF, read_cb, "authority");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_SYSTEM_ID)
|
||||||
|
if (!strncmp(name, "sysid_oui", nlen)) {
|
||||||
|
uint32_t oui = 0;
|
||||||
|
|
||||||
|
len = read_cb(store, &oui, sizeof(oui));
|
||||||
|
if (len < 0) {
|
||||||
|
LOG_ERR("Failed to read System ID OUI from storage (err %zd)", len);
|
||||||
|
} else {
|
||||||
|
sys_put_le24(oui, &dis_system_id[5]);
|
||||||
|
LOG_DBG("System ID OUI set to %06X", oui);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strncmp(name, "sysid_identifier", nlen)) {
|
||||||
|
uint64_t identifier = 0;
|
||||||
|
|
||||||
|
len = read_cb(store, &identifier, sizeof(identifier));
|
||||||
|
if (len < 0) {
|
||||||
|
LOG_ERR("Failed to read System ID identifier from storage (err %zd)", len);
|
||||||
|
} else {
|
||||||
|
sys_put_le40(identifier, &dis_system_id[0]);
|
||||||
|
LOG_DBG("System ID identifier set to %10llX", identifier);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_DIS_IEEE_RCDL)
|
||||||
|
if (!strncmp(name, "ieeercdl", nlen)) {
|
||||||
|
len = read_cb(store, &dis_ieee_rcdl, sizeof(dis_ieee_rcdl) - 1);
|
||||||
|
if (len < 0) {
|
||||||
|
LOG_ERR("Failed to read IEEE 11073-20601 Regulatory Certification Data "
|
||||||
|
"List from storage (err %zd)",
|
||||||
|
len);
|
||||||
|
} else {
|
||||||
|
dis_ieee_rcdl[len] = '\0';
|
||||||
|
|
||||||
|
LOG_DBG("IEEE 11073-20601 Regulatory Certification Data List set to %s",
|
||||||
|
dis_ieee_rcdl);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue