#include #include "ble.h" #include "host/ble_att.h" #include "host/ble_gatt.h" #include "host/ble_hs_mbuf.h" #include "nimble/hci_common.h" #include "os/os_mbuf.h" #include "esp_log.h" #include "gatt_svcs.h" #include "BLE_UUID.h" #include "configuration.h" #include "power_profiler.h" static struct char_pres_format current_char_pres_format = { .format = FORMAT_UINT32, .exponent = -6, .unit = AMPERE_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static struct char_pres_format raw_voltage_char_pres_format = { .format = FORMAT_UINT32, .exponent = -3, .unit = VOLTS_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static struct char_pres_format refrsh_rate_char_pres_format = { .format = FORMAT_UINT32, .exponent = -3, .unit = SECONDS_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static struct char_pres_format zero_cali_nsamp_char_pres_format = { .format = FORMAT_UINT32, .exponent = 0, .unit = UNITLESS_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static struct char_pres_format auto_range_char_pres_format = { .format = FORMAT_BOOL, .exponent = 0, .unit = UNITLESS_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static struct char_pres_format current_range_char_pres_format = { .format = FORMAT_INT32, .exponent = 0, .unit = UNITLESS_UNIT_UUID, .namespc = 1, .descrH = NSP_DESC_MAIN & 0xff, .descrL = (NSP_DESC_MAIN>>8) & 0xff, }; static int gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len, void *dst, uint16_t *len) { uint16_t om_len; int rc; om_len = OS_MBUF_PKTLEN(om); if (om_len < min_len || om_len > max_len) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); if (rc != 0) { return BLE_ATT_ERR_UNLIKELY; } return 0; } int gatt_char_access_cs(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_READ_CHR: ; struct ble_context *c_ctxt = arg; uint16_t id = c_ctxt->handle; uint32_t data = c_ctxt->meas->amperes[id]; rc = os_mbuf_append(ctxt->om, &data, sizeof(data)); break; case BLE_GATT_ACCESS_OP_READ_DSC: ; if(arg == NULL) // characteristic presentation format rc = os_mbuf_append(ctxt->om, ¤t_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); else{ struct ble_context *c_ctxt = arg; uint16_t handle = c_ctxt->handle; unsigned int gain = c_ctxt->meas_ctxt->inputs[handle].gain; rc = os_mbuf_append(ctxt->om, &gain, sizeof(gain)); } break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; } int gatt_char_access_ev(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_READ_CHR: ; struct ble_context *c_ctxt = arg; uint16_t id = c_ctxt->handle; uint32_t data = c_ctxt->meas->raw_volt[id]; rc = os_mbuf_append(ctxt->om, &data, sizeof(data)); break; case BLE_GATT_ACCESS_OP_READ_DSC: if(arg == NULL) // characteristic presentation format rc = os_mbuf_append(ctxt->om, &raw_voltage_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); else{ struct ble_context *c_ctxt = arg; uint16_t handle = c_ctxt->handle; unsigned int gain = c_ctxt->meas_ctxt->inputs[handle].gain; rc = os_mbuf_append(ctxt->om, &gain, sizeof(gain)); } break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; } int gatt_char_access_sampling_rate(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; struct ble_context *c_ctxt = arg; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_READ_CHR: ; rc = os_mbuf_append(ctxt->om, &c_ctxt->conf->refresh_delay, sizeof(c_ctxt->conf->refresh_delay)); break; case BLE_GATT_ACCESS_OP_WRITE_CHR: ; uint32_t data; rc = gatt_svr_chr_write(ctxt->om, sizeof(data), sizeof(data), &data, NULL); ESP_LOGI("BLE", "Refresh rate : %lu", data); c_ctxt->conf->refresh_delay = data; save_configuration_to_nvs(c_ctxt->conf); break; case BLE_GATT_ACCESS_OP_READ_DSC: rc = os_mbuf_append(ctxt->om, &refrsh_rate_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; } int gatt_char_access_zeros_cali(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; struct ble_context* c_ctxt = arg; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_WRITE_CHR: { switch (c_ctxt->handle){ case ZEROS_CALI_ID: start_zero_cali(c_ctxt->meas_ctxt, c_ctxt->conf->zero_cali_nsamp, c_ctxt->conf->offsets); save_configuration_to_nvs(c_ctxt->conf); break; case ZEROS_CALI_RESET: for(int i = 0; i < INPUTS_NUM; i++) c_ctxt->conf->offsets[i] = 0; save_configuration_to_nvs(c_ctxt->conf); ESP_LOGI(TAG, "offset zeroed %lu %lu %lu", c_ctxt->conf->offsets[0], c_ctxt->conf->offsets[1], c_ctxt->conf->offsets[2]); break; case ZEROS_CALI_NSAMP_ID: ; uint32_t data; rc = gatt_svr_chr_write(ctxt->om, sizeof(data), sizeof(data), &data, NULL); c_ctxt->conf->zero_cali_nsamp = data; save_configuration_to_nvs(c_ctxt->conf); break; } } break; case BLE_GATT_ACCESS_OP_READ_CHR: ; rc = os_mbuf_append(ctxt->om, &c_ctxt->conf->zero_cali_nsamp, sizeof(c_ctxt->conf->zero_cali_nsamp)); break; case BLE_GATT_ACCESS_OP_READ_DSC: ; rc = os_mbuf_append(ctxt->om, &zero_cali_nsamp_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; } int gatt_char_access_range(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; struct ble_context* c_ctxt = arg; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_WRITE_CHR: { switch (c_ctxt->handle){ case AUTO_RANGE_ID: ; uint8_t state; rc = gatt_svr_chr_write(ctxt->om, sizeof(state), sizeof(state), &state, NULL); c_ctxt->conf->auto_range = state; save_configuration_to_nvs(c_ctxt->conf); break; case CURRENT_RANGE_ID: ; int data; rc = gatt_svr_chr_write(ctxt->om, sizeof(data), sizeof(data), &data, NULL); ESP_LOGI(TAG, "new range %d", data); c_ctxt->conf->range = data; activate_range(c_ctxt->conf->ranges, data, c_ctxt->conf->ranges_num - 1); save_configuration_to_nvs(c_ctxt->conf); break; } } break; case BLE_GATT_ACCESS_OP_READ_CHR: { switch (c_ctxt->handle){ case AUTO_RANGE_ID: ; rc = os_mbuf_append(ctxt->om, &c_ctxt->conf->auto_range, sizeof(c_ctxt->conf->auto_range)); break; case CURRENT_RANGE_ID: rc = os_mbuf_append(ctxt->om, &c_ctxt->conf->range, sizeof(c_ctxt->conf->range)); ; break; } } break; case BLE_GATT_ACCESS_OP_READ_DSC: { switch (c_ctxt->handle){ case AUTO_RANGE_ID: ; rc = os_mbuf_append(ctxt->om, &auto_range_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); break; case CURRENT_RANGE_ID: ; rc = os_mbuf_append(ctxt->om, ¤t_range_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); break; } } break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; } int gatt_char_access_csf(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg){ int rc = 0; switch(ctxt->op){ case BLE_GATT_ACCESS_OP_READ_CHR: ; struct ble_context *c_ctxt = arg; uint32_t data = c_ctxt->meas->amperes_f; rc = os_mbuf_append(ctxt->om, &data, sizeof(data)); break; case BLE_GATT_ACCESS_OP_READ_DSC: ; rc = os_mbuf_append(ctxt->om, ¤t_char_pres_format, CHAR_PRESENTATION_FORMAT_SIZE); break; } return rc ? BLE_ATT_ERR_INSUFFICIENT_RES : 0; }