extern void ScanParamHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; sys_status rc = sys_status_success; switch(p_ind->handle) { case HANDLE_SCAN_INTERVAL_WINDOW: { scan_param_data.interval = BufReadUint16(&p_value); scan_param_data.window = BufReadUint16(&p_value); } break; case HANDLE_SCAN_REFRESH_C_CFG: { uint16 client_config = BufReadUint16(&p_value); /* Client Configuration is bit field value so ideally bitwise * comparison should be used but since the application supports only * notifications, direct comparison is being used. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { scan_param_data.refresh_client_config = client_config; /* Write Scan refresh Client configuration to NVM if the * device is bonded. */ Nvm_Write(&client_config, sizeof(gatt_client_config), scan_param_data.nvm_offset+ SCAN_PARAM_NVM_REFRESH_CLIENT_CONFIG_OFFSET); } else { /* INDICATION or RESERVED */ /* Return Error as only Notifications are supported */ rc = gatt_status_desc_improper_config; } } break; default: { rc = gatt_status_write_not_permitted; } break; } GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); }
extern void BatteryHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; uint16 client_config; sys_status rc = sys_status_success; switch(p_ind->handle) { case HANDLE_BATT_LEVEL_C_CFG: { client_config = BufReadUint16(&p_value); /* Client Configuration is bit field value so ideally bitwise * comparison should be used but since the application supports only * notifications, direct comparison is being used. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { g_batt_data.level_client_config = client_config; /* Write battery level client configuration to NVM if the * device is bonded. */ Nvm_Write(&client_config, sizeof(client_config), g_batt_data.nvm_offset + BATTERY_NVM_LEVEL_CLIENT_CONFIG_OFFSET); } else { /* INDICATION or RESERVED */ /* Return error as only notifications are supported */ rc = gatt_status_desc_improper_config; } } break; default: rc = gatt_status_write_not_permitted; break; } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); /* Send an update as soon as notifications are configured */ if(g_batt_data.level_client_config & gatt_client_config_notification) { /* Reset current battery level to an invalid value so that it * triggers notifications on reading the current battery level */ g_batt_data.level = 0xFF; /* 0 to 100: Valid value range */ BatteryUpdateLevel(p_ind->cid); } }
extern void BatteryHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; uint16 client_config; sys_status rc = sys_status_success; switch(p_ind->handle) { case HANDLE_BATT_LEVEL_C_CFG: { client_config = BufReadUint16(&p_value); if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { g_batt_data.level_client_config = client_config; /* Write batery level client configuration to NVM if the * device is bonded. */ if(AppIsDeviceBonded()) { Nvm_Write((uint16 *)&client_config, sizeof(client_config), g_batt_data.nvm_offset + BATTERY_NVM_LEVEL_CLIENT_CONFIG_OFFSET); } } else { /* INDICATION or RESERVED */ /* Return error as only notifications are supported */ rc = gatt_status_app_mask; } } break; default: { rc = gatt_status_write_not_permitted; } break; } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); /* Send an update as soon as notifications are configured */ if(g_batt_data.level_client_config == gatt_client_config_notification) { /* Reset current battery level to an invalid value so that it * triggers notifications on reading the current battery level */ g_batt_data.level = 0xFF; /* 0 to 100: Valid value range */ BatteryUpdateLevel(p_ind->cid); } }
/*----------------------------------------------------------------------------* * NAME * HandleAccessWrite * * DESCRIPTION * This function handles write operations on Battery Service attributes * maintained by the application and responds with the GATT_ACCESS_RSP * message. * * PARAMETERS * p_ind [in] Data received in GATT_ACCESS_IND message. * * RETURNS * Nothing *----------------------------------------------------------------------------*/ extern void BatteryHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; /* New attribute value */ uint16 client_config; /* Client configuration descriptor */ sys_status rc = sys_status_success; /* Function status */ switch(p_ind->handle) { case HANDLE_BATT_LEVEL_C_CFG: { /* Write the client configuration descriptor for the battery level * characteristic. */ client_config = BufReadUint16(&p_value); /* Only notifications are allowed for this client configuration * descriptor. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { g_batt_data.level_client_config = client_config; } else { /* INDICATION or RESERVED */ /* Return error as only notifications are supported */ rc = gatt_status_app_mask; } } break; default: rc = gatt_status_write_not_permitted; break; } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); /* Send an update as soon as notifications are configured */ if(g_batt_data.level_client_config == gatt_client_config_notification) { /* Reset current battery level to an invalid value so that it * triggers notifications on reading the current battery level */ g_batt_data.level = 0xFF; /* 0 to 100: Valid value range */ /* Update the battery level and send notification. */ BatteryUpdateLevel(p_ind->cid); } }
extern void GattHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint16 client_config; uint8 *p_value = p_ind->value; sys_status rc = gatt_status_write_not_permitted; if(p_ind->handle == HANDLE_SERVICE_CHANGED_CLIENT_CONFIG) { uint8 dev_index; dev_index = AppGetConnectedDeviceIndex(); client_config = BufReadUint16(&p_value); /* Client configuration is a bit field value, so ideally bit wise * comparison should be used but since the application supports only * indications or nothing, direct comparison should be used. */ if((client_config == gatt_client_config_indication) || (client_config == gatt_client_config_none)) { g_gatt_data.serv_changed_config[dev_index] = client_config; rc = sys_status_success; if(AppIsDeviceBonded(dev_index)) { /* Write to NVM the Service Changed Client Configuration value */ Nvm_Write((uint16*)&(g_gatt_data.serv_changed_config[dev_index]), sizeof(g_gatt_data.serv_changed_config[dev_index]), (g_gatt_data.nvm_offset + SERV_CHANGED_CLIENT_CONFIG_OFFSET(dev_index))); } } else { rc = gatt_status_desc_improper_config; } } /* Send Access Response */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); }
extern void HeartRateHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; gatt_client_config client_config; sys_status rc = sys_status_success; switch(p_ind->handle) { /* Heart Rate measurement characteristic client configuration is being * written */ case HANDLE_HEART_RATE_MEASUREMENT_C_CFG: { client_config = BufReadUint16(&p_value); /* Client Configuration is bit field value so ideally bitwise * comparison should be used but since the application supports only * notifications, direct comparison is being used. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { /* Store the new client configuration */ g_hr_serv_data.hr_meas_client_config = client_config; /* Write Heart Rate Measurement Client configuration to NVM if * the device is bonded. */ if(AppIsDeviceBonded()) { Nvm_Write((uint16*)&client_config, sizeof(client_config), g_hr_serv_data.nvm_offset + HR_NVM_HR_MEAS_CLIENT_CONFIG_OFFSET); } /* Start sending the HR measurement notifications if they are * not being sent currently. */ StartSendingHRMeasurements(); } else { /* INDICATION or RESERVED */ /* Return Error as only Notifications are supported */ rc = gatt_status_desc_improper_config; } break; } /* Heart Rate Control point is being written */ case HANDLE_HEART_RATE_CONTROL_POINT: { /* Extract the written value */ uint8 cntl_point_val = BufReadUint8(&p_value); /* Check if the HR client has reset the expended energy. */ if(cntl_point_val == hr_control_point_reset_energy) { /* Yes, it has. Make a note of it. */ g_hr_serv_data.energy_expended = 0; g_hr_serv_data.reset_energy_expended_received = TRUE; } else /* Reserved Value */ { rc = gatt_status_desc_improper_config; } break; } default: { /* Write is not permitted on any other characteristic/attribute */ rc = gatt_status_write_not_permitted; break; } } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); }
extern void HidHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint16 client_config, input_rpt_hndl; uint8 *p_value = p_ind->value; sys_status rc = sys_status_success; bool update_input_report_config = FALSE; switch(p_ind->handle) { case HANDLE_HID_INPUT_RPT_CLIENT_CONFIG: case HANDLE_HID_BOOT_INPUT_RPT_CLIENT_CONFIG: { /* Copy the value being written by the remote device to a local * variable */ client_config = BufReadUint16(&p_value); /* Client Configuration is bit field value so ideally bitwise * comparison should be used but since the application supports only * notifications, direct comparison is being used. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { /* CCCD of input report and boot input report have different * offsets at which their values are written into NVM */ uint16 offset; if(p_ind->handle == HANDLE_HID_INPUT_RPT_CLIENT_CONFIG) { hid_data.input_client_config = client_config; /* If Report mode set, update Input Report Configuration * for Report mode */ if(hid_data.report_mode) { update_input_report_config = TRUE; input_rpt_hndl = HANDLE_HID_INPUT_REPORT; } offset = hid_data.nvm_offset+ HID_NVM_INPUT_RPT_CLIENT_CONFIG_OFFSET; } else /* Input Boot Report Client Configuration */ { hid_data.input_boot_client_config = client_config; /* If Report mode not set, update Input Report Configuration * for Boot mode */ if(!hid_data.report_mode) { update_input_report_config = TRUE; input_rpt_hndl = HANDLE_HID_BOOT_INPUT_REPORT; } offset = hid_data.nvm_offset+ HID_NVM_INPUT_BOOT_RPT_CLIENT_CONFIG_OFFSET; } /* Write HID Input Report Client configuration or HID Input Boot * Report Client configuration to NVM if the devices are bonded. */ Nvm_Write(&client_config, sizeof(gatt_client_config), offset); /* Device shall only trigger Input reports (boot / main) if * notifications are enabled for characteristic corresponding * to the current protocol mode. */ if(update_input_report_config) { updateInputReportConfiguration(client_config, input_rpt_hndl); } } else { /* INDICATION or RESERVED */ /* Return Error as only Notifications are supported for * mouse application */ rc = gatt_status_desc_improper_config; } } break; case HANDLE_HID_CONTROL_POINT: { /* Copy the value being written by the remote device to a local * variable. */ uint8 control_op = BufReadUint8(&p_value); handleControlPointUpdate(control_op); } break; case HANDLE_HID_PROTOCOL_MODE: { /* Copy the value being written by the remote device to a local * variable. */ uint8 mode = BufReadUint8(&p_value); /* Update the protocol mode only if the value being written is not * the same as the already existing protocol mode. */ hid_protocol_mode old_mode = hid_data.report_mode; if(((mode == hid_boot_mode) || (mode == hid_report_mode)) && (mode != old_mode)) /* Change of Protocol Mode */ { if(mode == hid_boot_mode) { client_config = hid_data.input_boot_client_config; input_rpt_hndl = HANDLE_HID_BOOT_INPUT_REPORT; } else { client_config = hid_data.input_client_config; input_rpt_hndl = HANDLE_HID_INPUT_REPORT; } hid_data.report_mode = mode; /* After the protocol mode is updated, update the service * notification status from the notifications * on CCCD of the respective mode handles. */ updateInputReportConfiguration(client_config, input_rpt_hndl); } /* Else Ignore the value */ } break; case HANDLE_HID_FEATURE_REPORT: { /* Copy the value being written by the remote device to a local * variable. */ sensor_resolution resolution = BufReadUint8(&p_value); /* Update the mouse resolution. This is an example feature report. * Customers can define vendor specific feature reports and * implement their handling as per the requirements */ if(!SetSensorResolution(resolution)) { rc = gatt_status_att_val_oor; } } break; default: { /* No more IRQ characteristics in HID service */ rc = gatt_status_write_not_permitted; } break; } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); }
extern void HeartRateHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { uint8 *p_value = p_ind->value; gatt_client_config client_config; sys_status rc = sys_status_success; switch(p_ind->handle) { /* Heart Rate measurement characteristic client configuration is being * written */ case HANDLE_EEG_MEASUREMENT_C_CFG: { client_config = BufReadUint16(&p_value); /* Client Configuration is bit field value so ideally bitwise * comparison should be used but since the application supports only * notifications, direct comparison is being used. */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { /* Store the new client configuration */ g_eeg_serv_data.hr_meas_client_config = client_config; /* Write Heart Rate Measurement Client configuration to NVM if * the device is bonded. */ if(AppIsDeviceBonded()) { Nvm_Write((uint16*)&client_config, sizeof(client_config), g_eeg_serv_data.nvm_offset + HR_NVM_HR_MEAS_CLIENT_CONFIG_OFFSET); } /* Start sending the HR measurement notifications if they are * not being sent currently. */ StartSendingHRMeasurements(); } else { /* INDICATION or RESERVED */ /* Return Error as only Notifications are supported */ rc = gatt_status_desc_improper_config; } break; } /* EEG channels Control point is being written */ case HANDLE_EEG_CHANNELS: { /* Extract the written value */ g_eeg_serv_data.channel_map = BufReadUint16(&p_value); DebugWriteString("\n\rChannel map updated"); break; } case HANDLE_EEG_ACQUISITION_RATE: { g_eeg_serv_data.acquisition_rate = BufReadUint16(&p_value); TimerDelete(g_eeg_serv_data.acq_tmr); g_eeg_serv_data.acq_tmr = TimerCreate((uint32) (1000000/g_eeg_serv_data.acquisition_rate), TRUE, acquireData); DebugWriteString("\n\rAcq Rate changed"); break; } default: { /* Write is not permitted on any other characteristic/attribute */ rc = gatt_status_write_not_permitted; break; } } /* Send ACCESS RESPONSE */ GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); }
/*-----------------------------------------------------------------------------* * NAME * OtaHandleAccessWrite * * DESCRIPTION * Handle write-access requests from the Host where the characteristic * handle falls within the range of the OTAU Application Service. * * PARAMETERS * p_ind [in] Write request data * * RETURNS * Nothing *----------------------------------------------------------------------------*/ void OtaHandleAccessWrite(GATT_ACCESS_IND_T *p_ind) { sys_status rc = gatt_status_write_not_permitted; /* Function status */ switch (p_ind->handle) { case HANDLE_CSR_OTA_CURRENT_APP: { /* Set the index of the current application */ const uint8 app_id = p_ind->value[0]; /* New application index */ #if defined(USE_STATIC_RANDOM_ADDRESS) || defined(USE_RESOLVABLE_RANDOM_ADDRESS) BD_ADDR_T bd_addr; /* Bluetooth Device address */ GapGetRandomAddress(&bd_addr); #endif /* USE_STATIC_RANDOM_ADDRESS || USE_RESOLVABLE_RANDOM_ADDRESS */ rc = OtaWriteCurrentApp(app_id, IS_BONDED, &(CONN_HOST_ADDR), LINK_DIVERSIFIER, #if defined(USE_STATIC_RANDOM_ADDRESS) || defined(USE_RESOLVABLE_RANDOM_ADDRESS) &bd_addr, #else NULL, #endif CONNECTION_IRK, GattServiceChangedIndActive()); if (rc != sys_status_success) { /* Sanitise the result. If OtaWriteCurrentApp fails it will be * because one or more of the supplied parameters was invalid. */ rc = gatt_status_invalid_param_value; } } break; case HANDLE_CSR_OTA_READ_CS_BLOCK: /* Set the offset and length of a block of CS to read */ /* Validate input (expecting uint16[2]) */ if (p_ind->size_value == WORDS_TO_BYTES(sizeof(uint16[2]))) { const uint16 offset = BufReadUint16(&p_ind->value); data_transfer_data_length = (uint8)BufReadUint16(&p_ind->value); rc = readCsBlock(offset, data_transfer_data_length, data_transfer_memory); } else { rc = gatt_status_invalid_length; } break; case HANDLE_CSR_OTA_DATA_TRANSFER_CLIENT_CONFIG: { /* Modify the Data Transfer Client Characteristic Configuration * Descriptor */ const uint16 client_config = BufReadUint16(&p_ind->value); /* Requested descriptor value */ if((client_config == gatt_client_config_notification) || (client_config == gatt_client_config_none)) { data_transfer_configuration[0] = client_config; rc = sys_status_success; } else { /* INDICATION or RESERVED */ /* Return error as only notifications are supported */ rc = gatt_status_desc_improper_config; } } break; default: /* Writing to this characteristic is not permitted */ break; } GattAccessRsp(p_ind->cid, p_ind->handle, rc, 0, NULL); /* Perform any follow-up actions */ if (rc == sys_status_success) { switch (p_ind->handle) { case HANDLE_CSR_OTA_READ_CS_BLOCK: /* If this write action was to trigger a CS key read and * notifications have been enabled send the result now. */ if (data_transfer_configuration[0] == gatt_client_config_notification) { GattCharValueNotification(CONNECTION_CID, HANDLE_CSR_OTA_DATA_TRANSFER, data_transfer_data_length, data_transfer_memory); } break; case HANDLE_CSR_OTA_CURRENT_APP: /* If a new application index has been requested disconnect from * the Host and reset the device to run the new application. */ /* Record that the GATT database may be different after the * device has reset. */ GattOnOtaSwitch(); /* When the disconnect confirmation comes in, call OtaReset() */ g_ota_reset_required = TRUE; /* Disconnect from the Host */ GattDisconnectReq(CONNECTION_CID); break; default: /* No follow up action necessary */ break; } } }